Leak fixes.
* ma/reduce-heads-leakfix:
reduce_heads: fix memory leaks
builtin/merge-base: free commit lists
Junio C Hamano <gitster@pobox.com> <junio@twinsun.com>
Junio C Hamano <gitster@pobox.com> <junkio@cox.net>
Junio C Hamano <gitster@pobox.com> <junkio@twinsun.com>
+Kaartic Sivaraam <kaartic.sivaraam@gmail.com> <kaarticsivaraam91196@gmail.com>
Karl Wiberg <kha@treskal.com> Karl Hasselström
Karl Wiberg <kha@treskal.com> <kha@yoghurt.hemma.treskal.com>
Karsten Blees <blees@dcon.de> <karsten.blees@dcon.de>
packages:
- coccinelle
before_install:
- # "before_script" that builds Git is inherited from base job
+ before_script:
script: ci/run-static-analysis.sh
after_failure:
- env: Documentation
learned to take the 'unfold' and 'only' modifiers to normalize its
output, e.g. "git log --format=%(trailers:only,unfold)".
- * "gitweb" shows a link to visit the 'raw' contents of blbos in the
+ * "gitweb" shows a link to visit the 'raw' contents of blobs in the
history overview page.
* "[gc] rerereResolved = 5.days" used to be invalid, as the variable
* Conversion from uchar[20] to struct object_id continues.
* Start using selected c99 constructs in small, stable and
- essentialpart of the system to catch people who care about
+ essential part of the system to catch people who care about
older compilers that do not grok them.
* The filter-process interface learned to allow a process with long
latency give a "delayed" response.
- * Many uses of comparision callback function the hashmap API uses
+ * Many uses of comparison callback function the hashmap API uses
cast the callback function type when registering it to
hashmap_init(), which defeats the compile time type checking when
the callback interface changes (e.g. gaining more parameters).
--- /dev/null
+Git 2.16 Release Notes
+======================
+
+Backward compatibility notes and other notable changes.
+
+ * Use of an empty string as a pathspec element that is used for
+ 'everything matches' is now an error.
+
+
+Updates since v2.15
+-------------------
+
+UI, Workflows & Features
+
+ * An empty string as a pathspec element that means "everything"
+ i.e. 'git add ""', is now illegal. We started this by first
+ deprecating and warning a pathspec that has such an element in
+ 2.11 (Nov 2016).
+
+ * A hook script that is set unexecutable is simply ignored. Git
+ notifies when such a file is ignored, unless the message is
+ squelched via advice.ignoredHook configuration.
+
+ * "git pull" has been taught to accept "--[no-]signoff" option and
+ pass it down to "git merge".
+
+ * The "--push-option=<string>" option to "git push" now defaults to a
+ list of strings configured via push.pushOption variable.
+
+ * "gitweb" checks if a directory is searchable with Perl's "-x"
+ operator, which can be enhanced by using "filetest 'access'"
+ pragma, which now we do.
+
+ * "git stash save" has been deprecated in favour of "git stash push".
+
+
+Performance, Internal Implementation, Development Support etc.
+
+ * An earlier update made it possible to use an on-stack in-core
+ lockfile structure (as opposed to having to deliberately leak an
+ on-heap one). Many codepaths have been updated to take advantage
+ of this new facility.
+
+ * Calling cmd_foo() as if it is a general purpose helper function is
+ a no-no. Correct two instances of such to set an example.
+
+ * We try to see if somebody runs our test suite with a shell that
+ does not support "local" like bash/dash does.
+
+ * An early part of piece-by-piece rewrite of "git bisect" in C.
+
+ * GSoC to piece-by-piece rewrite "git submodule" in C.
+
+ * Optimize the code to find shortest unique prefix of object names.
+
+ * Pathspec-limited revision traversal was taught not to keep finding
+ unneeded differences once it knows two trees are different inside
+ given pathspec.
+
+ * Conversion from uchar[20] to struct object_id continues.
+
+ * Code cleanup.
+ (merge 62a24c8923 rs/hex-to-bytes-cleanup later to maint).
+
+ * A single-word "unsigned flags" in the diff options is being split
+ into a structure with many bitfields.
+ (merge 0d1e0e7801 bw/diff-opt-impl-to-bitfields later to maint).
+
+ * TravisCI build updates.
+ (merge c2154953b8 sg/travis-fixes later to maint).
+
+
+Also contains various documentation updates and code clean-ups.
+
+
+Fixes since v2.15
+-----------------
+
+ * "auto" as a value for the columnar output configuration ought to
+ judge "is the output consumed by humans?" with the same criteria as
+ "auto" for coloured output configuration, i.e. either the standard
+ output stream is going to tty, or a pager is in use. We forgot the
+ latter, which has been fixed.
+ (merge 965ff23a43 kd/auto-col-with-pager-fix later to maint).
+
+ * The experimental "color moved lines differently in diff output"
+ feature was buggy around "ignore whitespace changes" edges, whihch
+ has been corrected.
+ (merge b66b507292 jk/diff-color-moved-fix later to maint).
+
+ * Instead of using custom line comparison and hashing functions to
+ implement "moved lines" coloring in the diff output, use the pair
+ of these functions from lower-layer xdiff/ code.
+ (merge 01be97c2b2 sb/diff-color-moved-use-xdl-recmatch later to maint).
+
+ * Some codepaths did not check for errors when asking what branch the
+ HEAD points at, which have been fixed.
+ (merge dbd2b55cb7 jk/misc-resolve-ref-unsafe-fixes later to maint).
+
+ * "git commit", after making a commit, did not check for errors when
+ asking on what branch it made the commit, which has been correted.
+ (merge c26de08370 ao/check-resolve-ref-unsafe-result later to maint).
+
+ * "git status --ignored -u" did not stop at a working tree of a
+ separate project that is embedded in an ignored directory and
+ listed files in that other project, instead of just showing the
+ directory itself as ignored.
+ (merge fadb4820c4 js/submodule-in-excluded later to maint).
+
+ * A broken access to object databases in recent update to "git grep
+ --recurse-submodules" has been fixed.
+ (merge 9560e6245a bw/grep-recurse-submodules later to maint).
+
+ * A recent regression in "git rebase -i" that broke execution of git
+ commands from subdirectories via "exec" insn has been fixed.
+ (merge 09d7b6c6fa jk/rebase-i-exec-gitdir-fix later to maint).
+
+ * A (possibly flakey) test fix.
+ (merge cff48ccf2a jc/t5601-copy-workaround later to maint).
+
+ * "git check-ref-format --branch @{-1}" bit a "BUG()" when run
+ outside a repository for obvious reasons; clarify the documentation
+ and make sure we do not even try to expand the at-mark magic in
+ such a case, but still call the validation logic for branch names.
+ (merge 89dd32aedc jc/check-ref-format-oor later to maint).
+
+ * "git fetch --recurse-submodules" now knows that submodules can be
+ moved around in the superproject in addition to getting updated,
+ and finds the ones that need to be fetched accordingly.
+ (merge 4b4acedd61 hv/fetch-moved-submodules-on-demand later to maint).
+
+ * Command line completion (in contrib/) update.
+ (merge 6357d9d004 tb/complete-checkout later to maint).
+
+ * Description of blame.{showroot,blankboundary,showemail,date}
+ configuration variables have been added to "git config --help".
+ (merge de0bc11d13 sb/blame-config-doc later to maint).
+
+ * After an error from lstat(), diff_populate_filespec() function
+ sometimes still went ahead and used invalid data in struct stat,
+ which has been fixed.
+ (merge 10e0ca843d ao/diff-populate-filespec-lstat-errorpath-fix later to maint).
+
+ * UNC paths are also relevant in Cygwin builds and they are now
+ tested just like Mingw builds.
+ (merge f21d60b429 ad/5580-unc-tests-on-cygwin later to maint).
+
+ * Correct start-up sequence so that a repository could be placed
+ immediately under the root directory again (which was broken at
+ around Git 2.13).
+ (merge fa4d8c783d js/early-config later to maint).
+
+ * The credential helper for libsecret (in contrib/) has been improved
+ to allow possibly prompting the end user to unlock secrets that are
+ currently locked (otherwise the secrets may not be loaded).
+ (merge 9c109e9bbc dk/libsecret-unlock-to-load-fix later to maint).
+
+ * MinGW updates.
+ (merge 39bb86b4e5 js/mingw-full-version-in-resources later to maint).
+ (merge 601e1e7897 js/wincred-empty-cred later to maint).
+ (merge b2f55717c7 js/mingw-redirect-std-handles later to maint).
+
+ * Other minor doc, test and build updates and code cleanups.
+ (merge bab76141da cn/diff-indent-no-longer-is-experimental later to maint).
+ (merge 8684dde10d jm/relnotes-2.15-typofix later to maint).
+ (merge cd3f8e2fc2 ks/mailmap later to maint).
addEmbeddedRepo::
Advice on what to do when you've accidentally added one
git repo inside of another.
+ ignoredHook::
+ Advice shown if an hook is ignored because the hook is not
+ set as executable.
--
core.fileMode::
Tells 'git apply' how to handle whitespaces, in the same way
as the `--whitespace` option. See linkgit:git-apply[1].
+blame.showRoot::
+ Do not treat root commits as boundaries in linkgit:git-blame[1].
+ This option defaults to false.
+
+blame.blankBoundary::
+ Show blank commit object name for boundary commits in
+ linkgit:git-blame[1]. This option defaults to false.
+
+blame.showEmail::
+ Show the author email instead of author name in linkgit:git-blame[1].
+ This option defaults to false.
+
+blame.date::
+ Specifies the format used to output dates in linkgit:git-blame[1].
+ If unset the iso format is used. For supported values,
+ see the discussion of the `--date` option at linkgit:git-log[1].
+
branch.autoSetupMerge::
Tells 'git branch' and 'git checkout' to set up new branches
so that linkgit:git-pull[1] will appropriately merge from the
override a value from a lower-priority config file. An explicit
command-line flag always overrides this config option.
+push.pushOption::
+ When no `--push-option=<option>` argument is given from the
+ command line, `git push` behaves as if each <value> of
+ this variable is given as `--push-option=<value>`.
++
+This is a multi-valued variable, and an empty value can be used in a
+higher priority configuration file (e.g. `.git/config` in a
+repository) to clear the values inherited from a lower priority
+configuration files (e.g. `$HOME/.gitconfig`).
++
+--
+
+Example:
+
+/etc/gitconfig
+ push.pushoption = a
+ push.pushoption = b
+
+~/.gitconfig
+ push.pushoption = c
+
+repo/.git/config
+ push.pushoption =
+ push.pushoption = b
+
+This will result in only b (a and c are cleared).
+
+--
+
push.recurseSubmodules::
Make sure all submodule commits used by the revisions to be pushed
are available on a remote-tracking branch. If the value is 'check'
+++ /dev/null
---indent-heuristic::
---no-indent-heuristic::
- These are to help debugging and tuning experimental heuristics
- (which are off by default) that shift diff hunk boundaries to
- make patches easier to read.
Synonym for `-p --raw`.
endif::git-format-patch[]
-include::diff-heuristic-options.txt[]
+--indent-heuristic::
+ Enable the heuristic that shift diff hunk boundaries to make patches
+ easier to read. This is the default.
+
+--no-indent-heuristic::
+ Disable the indent heuristic.
--minimal::
Spend extra time to make sure the smallest possible
OPTIONS
-------
include::blame-options.txt[]
-include::diff-heuristic-options.txt[]
SEE ALSO
--------
abbreviated object name, use <n>+1 digits. Note that 1 column
is used for a caret to mark the boundary commit.
-include::diff-heuristic-options.txt[]
-
THE PORCELAIN FORMAT
--------------------
. at-open-brace `@{` is used as a notation to access a reflog entry.
-With the `--branch` option, it expands the ``previous branch syntax''
+With the `--branch` option, the command takes a name and checks if
+it can be used as a valid branch name (e.g. when creating a new
+branch). The rule `git check-ref-format --branch $name` implements
+may be stricter than what `git check-ref-format refs/heads/$name`
+says (e.g. a dash may appear at the beginning of a ref component,
+but it is explicitly forbidden at the beginning of a branch name).
+When run with `--branch` option in a repository, the input is first
+expanded for the ``previous branch syntax''
`@{-n}`. For example, `@{-1}` is a way to refer the last branch you
were on. This option should be used by porcelains to accept this
syntax anywhere a branch name is expected, so they can act as if you
(behind), "<>" (ahead and behind), or "=" (in sync). `:track`
also prints "[gone]" whenever unknown upstream ref is
encountered. Append `:track,nobracket` to show tracking
- information without brackets (i.e "ahead N, behind M"). Has
- no effect if the ref does not have tracking information
- associated with it. All the options apart from `nobracket`
- are mutually exclusive, but if used together the last option
- is selected.
+ information without brackets (i.e "ahead N, behind M").
++
+For any remote-tracking branch `%(upstream)`, `%(upstream:remotename)`
+and `%(upstream:remoteref)` refer to the name of the remote and the
+name of the tracked remote ref, respectively. In other words, the
+remote-tracking branch can be updated explicitly and individually by
+using the refspec `%(upstream:remoteref):%(upstream)` to fetch from
+`%(upstream:remotename)`.
++
+Has no effect if the ref does not have tracking information associated
+with it. All the options apart from `nobracket` are mutually exclusive,
+but if used together the last option is selected.
push::
The name of a local ref which represents the `@{push}`
location for the displayed ref. Respects `:short`, `:lstrip`,
- `:rstrip`, `:track`, and `:trackshort` options as `upstream`
- does. Produces an empty string if no `@{push}` ref is
- configured.
+ `:rstrip`, `:track`, `:trackshort`, `:remotename`, and `:remoteref`
+ options as `upstream` does. Produces an empty string if no `@{push}`
+ ref is configured.
HEAD::
'*' if HEAD matches current ref (the checked out branch), ' '
-------
include::merge-options.txt[]
---signoff::
- Add Signed-off-by line by the committer at the end of the commit
- log message. The meaning of a signoff depends on the project,
- but it typically certifies that committer has
- the rights to submit this work under the same license and
- agrees to a Developer Certificate of Origin
- (see http://developercertificate.org/ for more information).
-
-m <msg>::
Set the commit message to be used for the merge commit (in
case one is created).
Either all refs are updated, or on error, no refs are updated.
If the server does not support atomic pushes the push will fail.
--o::
---push-option::
+-o <option>::
+--push-option=<option>::
Transmit the given string to the server, which passes them to
the pre-receive as well as the post-receive hook. The given string
must not contain a NUL or LF character.
+ When multiple `--push-option=<option>` are given, they are
+ all sent to the other side in the order listed on the
+ command line.
+ When no `--push-option=<option>` is given from the command
+ line, the values of configuration variable `push.pushOption`
+ are used instead.
--receive-pack=<git-receive-pack>::
--exec=<git-receive-pack>::
'git stash' drop [-q|--quiet] [<stash>]
'git stash' ( pop | apply ) [--index] [-q|--quiet] [<stash>]
'git stash' branch <branchname> [<stash>]
-'git stash' save [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]
- [-u|--include-untracked] [-a|--all] [<message>]
'git stash' [push [-p|--patch] [-k|--[no-]keep-index] [-q|--quiet]
[-u|--include-untracked] [-a|--all] [-m|--message <message>]]
[--] [<pathspec>...]]
The modifications stashed away by this command can be listed with
`git stash list`, inspected with `git stash show`, and restored
(potentially on top of a different commit) with `git stash apply`.
-Calling `git stash` without any arguments is equivalent to `git stash save`.
+Calling `git stash` without any arguments is equivalent to `git stash push`.
A stash is by default listed as "WIP on 'branchname' ...", but
you can give a more descriptive message on the command line when
you create one.
OPTIONS
-------
-save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::
push [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [-m|--message <message>] [--] [<pathspec>...]::
Save your local modifications to a new 'stash entry' and roll them
The `--patch` option implies `--keep-index`. You can use
`--no-keep-index` to override this.
+save [-p|--patch] [-k|--[no-]keep-index] [-u|--include-untracked] [-a|--all] [-q|--quiet] [<message>]::
+
+ This option is deprecated in favour of 'git stash push'. It
+ differs from "stash push" in that it cannot take pathspecs,
+ and any non-option arguments form the message.
+
list [<options>]::
List the stash entries that you currently have. Each 'stash entry' is
Remove a single stashed state from the stash list and apply it
on top of the current working tree state, i.e., do the inverse
- operation of `git stash save`. The working directory must
+ operation of `git stash push`. The working directory must
match the index.
+
Applying the state can fail with conflicts; in this case, it is not
Like `pop`, but do not remove the state from the stash list. Unlike `pop`,
`<stash>` may be any commit that looks like a commit created by
- `stash save` or `stash create`.
+ `stash push` or `stash create`.
branch <branchname> [<stash>]::
`stash@{<revision>}`, it then drops the `<stash>`. When no `<stash>`
is given, applies the latest one.
+
-This is useful if the branch on which you ran `git stash save` has
+This is useful if the branch on which you ran `git stash push` has
changed enough that `git stash apply` fails due to conflicts. Since
the stash entry is applied on top of the commit that was HEAD at the
time `git stash` was run, it restores the originally stashed state
Testing partial commits::
-You can use `git stash save --keep-index` when you want to make two or
+You can use `git stash push --keep-index` when you want to make two or
more commits out of the changes in the work tree, and you want to test
each change before committing:
+
----------------------------------------------------------------
# ... hack hack hack ...
$ git add --patch foo # add just first part to the index
-$ git stash save --keep-index # save all other changes to the stash
+$ git stash push --keep-index # save all other changes to the stash
$ edit/build/test first part
$ git commit -m 'First part' # commit fully tested change
$ git stash pop # prepare to work on all other changes
(and suppresses the output of submodule summaries when the config option
`status.submoduleSummary` is set).
---ignored::
+--ignored[=<mode>]::
Show ignored files as well.
++
+The mode parameter is used to specify the handling of ignored files.
+It is optional: it defaults to 'traditional'.
++
+The possible options are:
++
+ - 'traditional' - Shows ignored files and directories, unless
+ --untracked-files=all is specifed, in which case
+ individual files in ignored directories are
+ displayed.
+ - 'no' - Show no ignored files.
+ - 'matching' - Shows ignored files and directories matching an
+ ignore pattern.
++
+When 'matching' mode is specified, paths that explicity match an
+ignored pattern are shown. If a directory matches an ignore pattern,
+then it is shown, but not paths contained in the ignored directory. If
+a directory does not match an ignore pattern, but all contents are
+ignored, then the directory is not shown, but all contents are shown.
-z::
Terminate entries with NUL, instead of LF. This implies
the background which do not want to cause lock contention with
other operations on the repository. Defaults to `1`.
+`GIT_REDIRECT_STDIN`::
+`GIT_REDIRECT_STDOUT`::
+`GIT_REDIRECT_STDERR`::
+ Windows-only: allow redirecting the standard input/output/error
+ handles to paths specified by the environment variables. This is
+ particularly useful in multi-threaded applications where the
+ canonical way to pass standard handles via `CreateProcess()` is
+ not an option because it would require the handles to be marked
+ inheritable (and consequently *every* spawned process would
+ inherit them, possibly blocking regular Git operations). The
+ primary intended use case is to use named pipes for communication
+ (e.g. `\\.\pipe\my-git-stdin-123`).
++
+Two special values are supported: `off` will simply close the
+corresponding standard handle, and if `GIT_REDIRECT_STDERR` is
+`2>&1`, standard error will be redirected to the same handle as
+standard output.
+
Discussion[[Discussion]]
------------------------
to split one big commit into several. Don't be afraid of making too
small or imperfect steps along the way. You can always go back later
and edit the commits with `git rebase --interactive` before you
-publish them. You can use `git stash save --keep-index` to run the
+publish them. You can use `git stash push --keep-index` to run the
test suite independent of other uncommitted changes; see the EXAMPLES
section of linkgit:git-stash[1].
With --no-log do not list one-line descriptions from the
actual commits being merged.
+--signoff::
+--no-signoff::
+ Add Signed-off-by line by the committer at the end of the commit
+ log message. The meaning of a signoff depends on the project,
+ but it typically certifies that committer has
+ the rights to submit this work under the same license and
+ agrees to a Developer Certificate of Origin
+ (see http://developercertificate.org/ for more information).
++
+With --no-signoff do not add a Signed-off-by line.
--stat::
-n::
`flags`::
- A bit-field of options (the `*IGNORED*` flags are mutually exclusive):
+ A bit-field of options:
`DIR_SHOW_IGNORED`:::
- Return just ignored files in `entries[]`, not untracked files.
+ Return just ignored files in `entries[]`, not untracked
+ files. This flag is mutually exclusive with
+ `DIR_SHOW_IGNORED_TOO`.
`DIR_SHOW_IGNORED_TOO`:::
- Similar to `DIR_SHOW_IGNORED`, but return ignored files in `ignored[]`
- in addition to untracked files in `entries[]`.
+ Similar to `DIR_SHOW_IGNORED`, but return ignored files in
+ `ignored[]` in addition to untracked files in
+ `entries[]`. This flag is mutually exclusive with
+ `DIR_SHOW_IGNORED`.
`DIR_KEEP_UNTRACKED_CONTENTS`:::
untracked contents of untracked directories are also returned in
`entries[]`.
+`DIR_SHOW_IGNORED_TOO_MODE_MATCHING`:::
+
+ Only has meaning if `DIR_SHOW_IGNORED_TOO` is also set; if
+ this is set, returns ignored files and directories that match
+ an exclude pattern. If a directory matches an exclude pattern,
+ then the directory is returned and the contained paths are
+ not. A directory that does not match an exclude pattern will
+ not be returned even if all of its contents are ignored. In
+ this case, the contents are returned as individual entries.
++
+If this is set, files and directories that explicity match an ignore
+pattern are reported. Implicity ignored directories (directories that
+do not match an ignore pattern, but whose contents are all ignored)
+are not reported, instead all of the contents are reported.
+
`DIR_COLLECT_IGNORED`:::
Special mode for git-add. Return ignored files in `ignored[]` and
work-in-progress changes.
------------------------------------------------
-$ git stash save "work in progress for foo feature"
+$ git stash push -m "work in progress for foo feature"
------------------------------------------------
This command will save your changes away to the `stash`, and
#!/bin/sh
GVF=GIT-VERSION-FILE
-DEF_VER=v2.15.0
+DEF_VER=v2.15.GIT
LF='
'
git.res: git.rc GIT-VERSION-FILE
$(QUIET_RC)$(RC) \
- $(join -DMAJOR= -DMINOR=, $(wordlist 1,2,$(subst -, ,$(subst ., ,$(GIT_VERSION))))) \
+ $(join -DMAJOR= -DMINOR= -DMICRO= -DPATCHLEVEL=, $(wordlist 1, 4, \
+ $(shell echo $(GIT_VERSION) 0 0 0 0 | tr '.a-zA-Z-' ' '))) \
-DGIT_VERSION="\\\"$(GIT_VERSION)\\\"" -i $< -o $@
# This makes sure we depend on the NO_PERL setting itself.
-Documentation/RelNotes/2.15.0.txt
\ No newline at end of file
+Documentation/RelNotes/2.16.0.txt
\ No newline at end of file
int advice_object_name_warning = 1;
int advice_rm_hints = 1;
int advice_add_embedded_repo = 1;
+int advice_ignored_hook = 1;
static struct {
const char *name;
{ "objectnamewarning", &advice_object_name_warning },
{ "rmhints", &advice_rm_hints },
{ "addembeddedrepo", &advice_add_embedded_repo },
+ { "ignoredhook", &advice_ignored_hook },
/* make this an alias for backward compatibility */
{ "pushnonfastforward", &advice_push_update_rejected }
extern int advice_object_name_warning;
extern int advice_rm_hints;
extern int advice_add_embedded_repo;
+extern int advice_ignored_hook;
int git_default_advice_config(const char *var, const char *value);
__attribute__((format (printf, 1, 2)))
}
int init_apply_state(struct apply_state *state,
- const char *prefix,
- struct lock_file *lock_file)
+ const char *prefix)
{
memset(state, 0, sizeof(*state));
state->prefix = prefix;
- state->lock_file = lock_file;
- state->newfd = -1;
state->apply = 1;
state->line_termination = '\n';
state->p_value = 1;
}
if (state->check_index)
state->unsafe_paths = 0;
- if (!state->lock_file)
- return error("BUG: state->lock_file should not be NULL");
if (state->apply_verbosity <= verbosity_silent) {
state->saved_error_routine = get_error_routine();
state->apply = 0;
state->update_index = state->check_index && state->apply;
- if (state->update_index && state->newfd < 0) {
+ if (state->update_index && !is_lock_file_locked(&state->lock_file)) {
if (state->index_file)
- state->newfd = hold_lock_file_for_update(state->lock_file,
- state->index_file,
- LOCK_DIE_ON_ERROR);
+ hold_lock_file_for_update(&state->lock_file,
+ state->index_file,
+ LOCK_DIE_ON_ERROR);
else
- state->newfd = hold_locked_index(state->lock_file, LOCK_DIE_ON_ERROR);
+ hold_locked_index(&state->lock_file, LOCK_DIE_ON_ERROR);
}
if (state->check_index && read_apply_cache(state) < 0) {
}
if (state->update_index) {
- res = write_locked_index(&the_index, state->lock_file, COMMIT_LOCK);
+ res = write_locked_index(&the_index, &state->lock_file, COMMIT_LOCK);
if (res) {
error(_("Unable to write new index file"));
res = -128;
goto end;
}
- state->newfd = -1;
}
res = !!errs;
end:
- if (state->newfd >= 0) {
- rollback_lock_file(state->lock_file);
- state->newfd = -1;
- }
+ rollback_lock_file(&state->lock_file);
if (state->apply_verbosity <= verbosity_silent) {
set_error_routine(state->saved_error_routine);
struct apply_state {
const char *prefix;
- /* These are lock_file related */
- struct lock_file *lock_file;
- int newfd;
+ /* Lock file */
+ struct lock_file lock_file;
/* These control what gets looked at and modified */
int apply; /* this is not a dry-run */
int *force_apply, int *options,
const char * const *apply_usage);
extern int init_apply_state(struct apply_state *state,
- const char *prefix,
- struct lock_file *lock_file);
+ const char *prefix);
extern void clear_apply_state(struct apply_state *state);
extern int check_apply_state(struct apply_state *state, int force_apply);
const char *colon = strchrnul(name, ':');
int refnamelen = colon - name;
- if (!dwim_ref(name, refnamelen, oid.hash, &ref))
+ if (!dwim_ref(name, refnamelen, &oid, &ref))
die("no such ref: %.*s", refnamelen, name);
free(ref);
}
add_name_decoration(DECORATION_NONE, buf.buf, obj);
p->item = array[i].commit;
- p = p->next;
+ if (i < cnt - 1)
+ p = p->next;
}
- if (p)
- p->next = NULL;
+ free_commit_list(p->next);
+ p->next = NULL;
strbuf_release(&buf);
free(array);
return list;
return best_bisection_sorted(list, nr);
}
-struct commit_list *find_bisection(struct commit_list *list,
- int *reaches, int *all,
- int find_all)
+void find_bisection(struct commit_list **commit_list, int *reaches,
+ int *all, int find_all)
{
int nr, on_list;
- struct commit_list *p, *best, *next, *last;
+ struct commit_list *list, *p, *best, *next, *last;
int *weights;
- show_list("bisection 2 entry", 0, 0, list);
+ show_list("bisection 2 entry", 0, 0, *commit_list);
/*
* Count the number of total and tree-changing items on the
* list, while reversing the list.
*/
- for (nr = on_list = 0, last = NULL, p = list;
+ for (nr = on_list = 0, last = NULL, p = *commit_list;
p;
p = next) {
unsigned flags = p->item->object.flags;
next = p->next;
- if (flags & UNINTERESTING)
+ if (flags & UNINTERESTING) {
+ free(p);
continue;
+ }
p->next = last;
last = p;
if (!(flags & TREESAME))
/* Do the real work of finding bisection commit. */
best = do_find_bisection(list, nr, weights, find_all);
if (best) {
- if (!find_all)
+ if (!find_all) {
+ list->item = best->item;
+ free_commit_list(list->next);
+ best = list;
best->next = NULL;
+ }
*reaches = weight(best);
}
free(weights);
- return best;
+ *commit_list = best;
}
static int register_ref(const char *refname, const struct object_id *oid,
static GIT_PATH_FUNC(git_path_bisect_names, "BISECT_NAMES")
static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
+static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
+static GIT_PATH_FUNC(git_path_bisect_run, "BISECT_RUN")
+static GIT_PATH_FUNC(git_path_bisect_start, "BISECT_START")
+static GIT_PATH_FUNC(git_path_bisect_log, "BISECT_LOG")
static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
+static GIT_PATH_FUNC(git_path_head_name, "head-name")
static void read_bisect_paths(struct argv_array *array)
{
char bisect_rev_hex[GIT_MAX_HEXSZ + 1];
memcpy(bisect_rev_hex, oid_to_hex(bisect_rev), GIT_SHA1_HEXSZ + 1);
- update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev->hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+ update_ref(NULL, "BISECT_EXPECTED_REV", bisect_rev, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
argv_checkout[2] = bisect_rev_hex;
if (no_checkout) {
- update_ref(NULL, "BISECT_HEAD", bisect_rev->hash, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+ update_ref(NULL, "BISECT_HEAD", bisect_rev, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
} else {
int res;
res = run_command_v_opt(argv_checkout, RUN_GIT_CMD);
bisect_common(&revs);
- revs.commits = find_bisection(revs.commits, &reaches, &all,
- !!skipped_revs.nr);
+ find_bisection(&revs.commits, &reaches, &all, !!skipped_revs.nr);
revs.commits = managed_skipped(revs.commits, &tried);
if (!revs.commits) {
return (e < 3 * x) ? n : n - 1;
}
+
+static int mark_for_removal(const char *refname, const struct object_id *oid,
+ int flag, void *cb_data)
+{
+ struct string_list *refs = cb_data;
+ char *ref = xstrfmt("refs/bisect%s", refname);
+ string_list_append(refs, ref);
+ return 0;
+}
+
+int bisect_clean_state(void)
+{
+ int result = 0;
+
+ /* There may be some refs packed during bisection */
+ struct string_list refs_for_removal = STRING_LIST_INIT_NODUP;
+ for_each_ref_in("refs/bisect", mark_for_removal, (void *) &refs_for_removal);
+ string_list_append(&refs_for_removal, xstrdup("BISECT_HEAD"));
+ result = delete_refs("bisect: remove", &refs_for_removal, REF_NO_DEREF);
+ refs_for_removal.strdup_strings = 1;
+ string_list_clear(&refs_for_removal, 0);
+ unlink_or_warn(git_path_bisect_expected_rev());
+ unlink_or_warn(git_path_bisect_ancestors_ok());
+ unlink_or_warn(git_path_bisect_log());
+ unlink_or_warn(git_path_bisect_names());
+ unlink_or_warn(git_path_bisect_run());
+ unlink_or_warn(git_path_bisect_terms());
+ /* Cleanup head-name if it got left by an old version of git-bisect */
+ unlink_or_warn(git_path_head_name());
+ /*
+ * Cleanup BISECT_START last to support the --no-checkout option
+ * introduced in the commit 4796e823a.
+ */
+ unlink_or_warn(git_path_bisect_start());
+
+ return result;
+}
#ifndef BISECT_H
#define BISECT_H
-extern struct commit_list *find_bisection(struct commit_list *list,
- int *reaches, int *all,
- int find_all);
+/*
+ * Find bisection. If something is found, `reaches` will be the number of
+ * commits that the best commit reaches. `all` will be the count of
+ * non-SAMETREE commits. If nothing is found, `list` will be NULL.
+ * Otherwise, it will be either all non-SAMETREE commits or the single
+ * best commit, as chosen by `find_all`.
+ */
+extern void find_bisection(struct commit_list **list, int *reaches, int *all,
+ int find_all);
extern struct commit_list *filter_skipped(struct commit_list *list,
struct commit_list **tried,
extern void read_bisect_terms(const char **bad, const char **good);
+extern int bisect_clean_state(void);
+
#endif
commit->date = now;
parent_tail = &commit->parents;
- if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL))
+ if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
die("no such ref: HEAD");
parent_tail = append_parent(parent_tail, &head_oid);
switch (st.st_mode & S_IFMT) {
case S_IFREG:
- if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
+ if (opt->flags.allow_textconv &&
textconv_object(read_from, mode, &null_oid, 0, &buf_ptr, &buf_len))
strbuf_attach(&buf, buf_ptr, buf_len, buf_len + 1);
else if (strbuf_read_file(&buf, read_from, st.st_size) != st.st_size)
unsigned long file_size;
(*num_read_blob)++;
- if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV) &&
+ if (opt->flags.allow_textconv &&
textconv_object(o->path, o->mode, &o->blob_oid, 1, &file->ptr, &file_size))
;
else
* same and diff-tree is fairly efficient about this.
*/
diff_setup(&diff_opts);
- DIFF_OPT_SET(&diff_opts, RECURSIVE);
+ diff_opts.flags.recursive = 1;
diff_opts.detect_rename = 0;
diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
paths[0] = origin->path;
int i;
diff_setup(&diff_opts);
- DIFF_OPT_SET(&diff_opts, RECURSIVE);
+ diff_opts.flags.recursive = 1;
diff_opts.detect_rename = DIFF_DETECT_RENAME;
diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
diff_opts.single_follow = origin->path;
return; /* nothing remains for this target */
diff_setup(&diff_opts);
- DIFF_OPT_SET(&diff_opts, RECURSIVE);
+ diff_opts.flags.recursive = 1;
diff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;
diff_setup_done(&diff_opts);
if ((opt & PICKAXE_BLAME_COPY_HARDEST)
|| ((opt & PICKAXE_BLAME_COPY_HARDER)
&& (!porigin || strcmp(target->path, porigin->path))))
- DIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);
+ diff_opts.flags.find_copies_harder = 1;
if (is_null_oid(&target->commit->object.oid))
do_diff_cache(&parent->tree->object.oid, &diff_opts);
&target->commit->tree->object.oid,
"", &diff_opts);
- if (!DIFF_OPT_TST(&diff_opts, FIND_COPIES_HARDER))
+ if (!diff_opts.flags.find_copies_harder)
diffcore_std(&diff_opts);
do {
return NULL;
/* Do we have HEAD? */
- if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL))
+ if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
return NULL;
head_commit = lookup_commit_reference_gently(&head_oid, 1);
if (!head_commit)
if (fill_blob_sha1_and_mode(o))
die(_("no such path %s in %s"), path, final_commit_name);
- if (DIFF_OPT_TST(&sb->revs->diffopt, ALLOW_TEXTCONV) &&
+ if (sb->revs->diffopt.flags.allow_textconv &&
textconv_object(path, o->mode, &o->blob_oid, 1, (char **) &sb->final_buf,
&sb->final_buf_size))
;
die(_("Not a valid object name: '%s'."), start_name);
}
- switch (dwim_ref(start_name, strlen(start_name), oid.hash, &real_ref)) {
+ switch (dwim_ref(start_name, strlen(start_name), &oid, &real_ref)) {
case 0:
/* Not branching from any existing branch */
if (explicit_tracking)
transaction = ref_transaction_begin(&err);
if (!transaction ||
ref_transaction_update(transaction, ref.buf,
- oid.hash, forcing ? NULL : null_sha1,
+ &oid, forcing ? NULL : &null_oid,
0, msg, &err) ||
ref_transaction_commit(transaction, &err))
die("%s", err.buf);
rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
rev.diffopt.format_callback = update_callback;
rev.diffopt.format_callback_data = &data;
- rev.diffopt.flags |= DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG;
+ rev.diffopt.flags.override_submodule_config = 1;
rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
clear_pathspec(&rev.prune_data);
argc = setup_revisions(argc, argv, &rev, NULL);
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
rev.diffopt.use_color = 0;
- DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
+ rev.diffopt.flags.ignore_dirty_submodules = 1;
out = open(file, O_CREAT | O_WRONLY, 0666);
if (out < 0)
die(_("Could not open '%s' for writing."), file);
if (!get_oid("HEAD", &curr_head)) {
write_state_text(state, "abort-safety", oid_to_hex(&curr_head));
if (!state->rebasing)
- update_ref_oid("am", "ORIG_HEAD", &curr_head, NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ update_ref("am", "ORIG_HEAD", &curr_head, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
} else {
write_state_text(state, "abort-safety", "");
if (!state->rebasing)
*/
static void refresh_and_write_cache(void)
{
- struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
+ struct lock_file lock_file = LOCK_INIT;
- hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
refresh_cache(REFRESH_QUIET);
- if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write index file"));
}
struct diff_options opt;
diff_setup(&opt);
- DIFF_OPT_SET(&opt, EXIT_WITH_STATUS);
+ opt.flags.exit_with_status = 1;
if (!sb)
- DIFF_OPT_SET(&opt, QUICK);
+ opt.flags.quick = 1;
do_diff_cache(&head, &opt);
diffcore_std(&opt);
for (i = 0; sb && i < diff_queued_diff.nr; i++) {
strbuf_addstr(sb, diff_queued_diff.queue[i]->two->path);
}
diff_flush(&opt);
- return DIFF_OPT_TST(&opt, HAS_CHANGES) != 0;
+ return opt.flags.has_changes != 0;
} else {
for (i = 0; sb && i < active_nr; i++) {
if (i)
rev_info.show_root_diff = 1;
rev_info.diffopt.output_format = DIFF_FORMAT_PATCH;
rev_info.no_commit_id = 1;
- DIFF_OPT_SET(&rev_info.diffopt, BINARY);
- DIFF_OPT_SET(&rev_info.diffopt, FULL_INDEX);
+ rev_info.diffopt.flags.binary = 1;
+ rev_info.diffopt.flags.full_index = 1;
rev_info.diffopt.use_color = 0;
rev_info.diffopt.file = fp;
rev_info.diffopt.close_file = 1;
struct argv_array apply_opts = ARGV_ARRAY_INIT;
struct apply_state apply_state;
int res, opts_left;
- static struct lock_file lock_file;
int force_apply = 0;
int options = 0;
- if (init_apply_state(&apply_state, NULL, &lock_file))
+ if (init_apply_state(&apply_state, NULL))
die("BUG: init_apply_state() failed");
argv_array_push(&apply_opts, "apply");
strbuf_addf(&sb, "%s: %.*s", reflog_msg, linelen(state->msg),
state->msg);
- update_ref_oid(sb.buf, "HEAD", &commit, old_oid, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ update_ref(sb.buf, "HEAD", &commit, old_oid, 0,
+ UPDATE_REFS_DIE_ON_ERR);
if (state->rebasing) {
FILE *fp = xfopen(am_path(state, "rewritten"), "a");
*/
static int fast_forward_to(struct tree *head, struct tree *remote, int reset)
{
- struct lock_file *lock_file;
+ struct lock_file lock_file = LOCK_INIT;
struct unpack_trees_options opts;
struct tree_desc t[2];
if (parse_tree(head) || parse_tree(remote))
return -1;
- lock_file = xcalloc(1, sizeof(struct lock_file));
- hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
refresh_cache(REFRESH_QUIET);
init_tree_desc(&t[1], remote->buffer, remote->size);
if (unpack_trees(2, t, &opts)) {
- rollback_lock_file(lock_file);
+ rollback_lock_file(&lock_file);
return -1;
}
- if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
return 0;
*/
static int merge_tree(struct tree *tree)
{
- struct lock_file *lock_file;
+ struct lock_file lock_file = LOCK_INIT;
struct unpack_trees_options opts;
struct tree_desc t[1];
if (parse_tree(tree))
return -1;
- lock_file = xcalloc(1, sizeof(struct lock_file));
- hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
memset(&opts, 0, sizeof(opts));
opts.head_idx = 1;
init_tree_desc(&t[0], tree->buffer, tree->size);
if (unpack_trees(1, t, &opts)) {
- rollback_lock_file(lock_file);
+ rollback_lock_file(&lock_file);
return -1;
}
- if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
return 0;
am_rerere_clear();
- curr_branch = resolve_refdup("HEAD", 0, curr_head.hash, NULL);
+ curr_branch = resolve_refdup("HEAD", 0, &curr_head, NULL);
has_curr_head = curr_branch && !is_null_oid(&curr_head);
if (!has_curr_head)
hashcpy(curr_head.hash, EMPTY_TREE_SHA1_BIN);
clean_index(&curr_head, &orig_head);
if (has_orig_head)
- update_ref_oid("am --abort", "HEAD", &orig_head,
- has_curr_head ? &curr_head : NULL, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ update_ref("am --abort", "HEAD", &orig_head,
+ has_curr_head ? &curr_head : NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
else if (curr_branch)
- delete_ref(NULL, curr_branch, NULL, REF_NODEREF);
+ delete_ref(NULL, curr_branch, NULL, REF_NO_DEREF);
free(curr_branch);
am_destroy(state);
NULL
};
-static struct lock_file lock_file;
-
int cmd_apply(int argc, const char **argv, const char *prefix)
{
int force_apply = 0;
int ret;
struct apply_state state;
- if (init_apply_state(&state, prefix, &lock_file))
+ if (init_apply_state(&state, prefix))
exit(128);
argc = apply_parse_options(argc, argv,
#include "cache.h"
#include "parse-options.h"
#include "bisect.h"
+#include "refs.h"
+
+static GIT_PATH_FUNC(git_path_bisect_terms, "BISECT_TERMS")
+static GIT_PATH_FUNC(git_path_bisect_expected_rev, "BISECT_EXPECTED_REV")
+static GIT_PATH_FUNC(git_path_bisect_ancestors_ok, "BISECT_ANCESTORS_OK")
static const char * const git_bisect_helper_usage[] = {
N_("git bisect--helper --next-all [--no-checkout]"),
+ N_("git bisect--helper --write-terms <bad_term> <good_term>"),
+ N_("git bisect--helper --bisect-clean-state"),
NULL
};
+/*
+ * Check whether the string `term` belongs to the set of strings
+ * included in the variable arguments.
+ */
+LAST_ARG_MUST_BE_NULL
+static int one_of(const char *term, ...)
+{
+ int res = 0;
+ va_list matches;
+ const char *match;
+
+ va_start(matches, term);
+ while (!res && (match = va_arg(matches, const char *)))
+ res = !strcmp(term, match);
+ va_end(matches);
+
+ return res;
+}
+
+static int check_term_format(const char *term, const char *orig_term)
+{
+ int res;
+ char *new_term = xstrfmt("refs/bisect/%s", term);
+
+ res = check_refname_format(new_term, 0);
+ free(new_term);
+
+ if (res)
+ return error(_("'%s' is not a valid term"), term);
+
+ if (one_of(term, "help", "start", "skip", "next", "reset",
+ "visualize", "replay", "log", "run", "terms", NULL))
+ return error(_("can't use the builtin command '%s' as a term"), term);
+
+ /*
+ * In theory, nothing prevents swapping completely good and bad,
+ * but this situation could be confusing and hasn't been tested
+ * enough. Forbid it for now.
+ */
+
+ if ((strcmp(orig_term, "bad") && one_of(term, "bad", "new", NULL)) ||
+ (strcmp(orig_term, "good") && one_of(term, "good", "old", NULL)))
+ return error(_("can't change the meaning of the term '%s'"), term);
+
+ return 0;
+}
+
+static int write_terms(const char *bad, const char *good)
+{
+ FILE *fp = NULL;
+ int res;
+
+ if (!strcmp(bad, good))
+ return error(_("please use two different terms"));
+
+ if (check_term_format(bad, "bad") || check_term_format(good, "good"))
+ return -1;
+
+ fp = fopen(git_path_bisect_terms(), "w");
+ if (!fp)
+ return error_errno(_("could not open the file BISECT_TERMS"));
+
+ res = fprintf(fp, "%s\n%s\n", bad, good);
+ res |= fclose(fp);
+ return (res < 0) ? -1 : 0;
+}
+
+static int is_expected_rev(const char *expected_hex)
+{
+ struct strbuf actual_hex = STRBUF_INIT;
+ int res = 0;
+ if (strbuf_read_file(&actual_hex, git_path_bisect_expected_rev(), 0) >= 40) {
+ strbuf_trim(&actual_hex);
+ res = !strcmp(actual_hex.buf, expected_hex);
+ }
+ strbuf_release(&actual_hex);
+ return res;
+}
+
+static void check_expected_revs(const char **revs, int rev_nr)
+{
+ int i;
+
+ for (i = 0; i < rev_nr; i++) {
+ if (!is_expected_rev(revs[i])) {
+ unlink_or_warn(git_path_bisect_ancestors_ok());
+ unlink_or_warn(git_path_bisect_expected_rev());
+ }
+ }
+}
+
int cmd_bisect__helper(int argc, const char **argv, const char *prefix)
{
- int next_all = 0;
+ enum {
+ NEXT_ALL = 1,
+ WRITE_TERMS,
+ BISECT_CLEAN_STATE,
+ CHECK_EXPECTED_REVS
+ } cmdmode = 0;
int no_checkout = 0;
struct option options[] = {
- OPT_BOOL(0, "next-all", &next_all,
- N_("perform 'git bisect next'")),
+ OPT_CMDMODE(0, "next-all", &cmdmode,
+ N_("perform 'git bisect next'"), NEXT_ALL),
+ OPT_CMDMODE(0, "write-terms", &cmdmode,
+ N_("write the terms to .git/BISECT_TERMS"), WRITE_TERMS),
+ OPT_CMDMODE(0, "bisect-clean-state", &cmdmode,
+ N_("cleanup the bisection state"), BISECT_CLEAN_STATE),
+ OPT_CMDMODE(0, "check-expected-revs", &cmdmode,
+ N_("check for expected revs"), CHECK_EXPECTED_REVS),
OPT_BOOL(0, "no-checkout", &no_checkout,
N_("update BISECT_HEAD instead of checking out the current commit")),
OPT_END()
argc = parse_options(argc, argv, prefix, options,
git_bisect_helper_usage, 0);
- if (!next_all)
+ if (!cmdmode)
usage_with_options(git_bisect_helper_usage, options);
- /* next-all */
- return bisect_next_all(prefix, no_checkout);
+ switch (cmdmode) {
+ case NEXT_ALL:
+ return bisect_next_all(prefix, no_checkout);
+ case WRITE_TERMS:
+ if (argc != 2)
+ return error(_("--write-terms requires two arguments"));
+ return write_terms(argv[0], argv[1]);
+ case BISECT_CLEAN_STATE:
+ if (argc != 0)
+ return error(_("--bisect-clean-state requires no arguments"));
+ return bisect_clean_state();
+ case CHECK_EXPECTED_REVS:
+ check_expected_revs(argv, argc);
+ return 0;
+ default:
+ return error("BUG: unknown subcommand '%d'", cmdmode);
+ }
+ return 0;
}
git_config(git_blame_config, &output_option);
init_revisions(&revs, NULL);
revs.date_mode = blame_date_mode;
- DIFF_OPT_SET(&revs.diffopt, ALLOW_TEXTCONV);
- DIFF_OPT_SET(&revs.diffopt, FOLLOW_RENAMES);
+ revs.diffopt.flags.allow_textconv = 1;
+ revs.diffopt.flags.follow_renames = 1;
save_commit_buffer = 0;
dashdash_pos = 0;
parse_revision_opt(&revs, &ctx, options, blame_opt_usage);
}
parse_done:
- no_whole_file_rename = !DIFF_OPT_TST(&revs.diffopt, FOLLOW_RENAMES);
+ no_whole_file_rename = !revs.diffopt.flags.follow_renames;
xdl_opts |= revs.diffopt.xdl_opts & XDF_INDENT_HEURISTIC;
- DIFF_OPT_CLR(&revs.diffopt, FOLLOW_RENAMES);
+ revs.diffopt.flags.follow_renames = 0;
argc = parse_options_end(&ctx);
if (incremental || (output_option & OUTPUT_PORCELAIN)) {
}
blame_date_width -= 1; /* strip the null */
- if (DIFF_OPT_TST(&revs.diffopt, FIND_COPIES_HARDER))
+ if (revs.diffopt.flags.find_copies_harder)
opt |= (PICKAXE_BLAME_COPY | PICKAXE_BLAME_MOVE |
PICKAXE_BLAME_COPY_HARDER);
if (upstream &&
(reference_name = reference_name_to_free =
resolve_refdup(upstream, RESOLVE_REF_READING,
- oid.hash, NULL)) != NULL)
+ &oid, NULL)) != NULL)
reference_rev = lookup_commit_reference(&oid);
}
if (!reference_rev)
RESOLVE_REF_READING
| RESOLVE_REF_NO_RECURSE
| RESOLVE_REF_ALLOW_BAD_NAME,
- oid.hash, &flags);
+ &oid, &flags);
if (!target) {
error(remote_branch
? _("remote-tracking branch '%s' not found.")
goto next;
}
- if (delete_ref(NULL, name, is_null_oid(&oid) ? NULL : oid.hash,
- REF_NODEREF)) {
+ if (delete_ref(NULL, name, is_null_oid(&oid) ? NULL : &oid,
+ REF_NO_DEREF)) {
error(remote_branch
? _("Error deleting remote-tracking branch '%s'")
: _("Error deleting branch '%s'"),
track = git_branch_track;
- head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+ head = resolve_refdup("HEAD", 0, &head_oid, NULL);
if (!head)
die(_("Failed to resolve HEAD as a valid ref."));
if (!strcmp(head, "HEAD"))
static int check_ref_format_branch(const char *arg)
{
struct strbuf sb = STRBUF_INIT;
+ const char *name;
int nongit;
setup_git_directory_gently(&nongit);
- if (strbuf_check_branch_ref(&sb, arg))
+ if (strbuf_check_branch_ref(&sb, arg) ||
+ !skip_prefix(sb.buf, "refs/heads/", &name))
die("'%s' is not a valid branch name", arg);
- printf("%s\n", sb.buf + 11);
+ printf("%s\n", name);
strbuf_release(&sb);
return 0;
}
NULL
};
-static struct lock_file lock_file;
-
static int option_parse_stage(const struct option *opt,
const char *arg, int unset)
{
int cmd_checkout_index(int argc, const char **argv, const char *prefix)
{
int i;
- int newfd = -1;
+ struct lock_file lock_file = LOCK_INIT;
int all = 0;
int read_from_stdin = 0;
int prefix_length;
if (index_opt && !state.base_dir_len && !to_tempfile) {
state.refresh_cache = 1;
state.istate = &the_index;
- newfd = hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
+ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
}
/* Check out named files first */
if (all)
checkout_all(prefix, prefix_length);
- if (0 <= newfd &&
+ if (is_lock_file_locked(&lock_file) &&
write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die("Unable to write new index file");
return 0;
struct object_id rev;
struct commit *head;
int errs = 0;
- struct lock_file *lock_file;
+ struct lock_file lock_file = LOCK_INIT;
if (opts->track != BRANCH_TRACK_UNSPECIFIED)
die(_("'%s' cannot be used with updating paths"), "--track");
return run_add_interactive(revision, "--patch=checkout",
&opts->pathspec);
- lock_file = xcalloc(1, sizeof(struct lock_file));
-
- hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
if (read_cache_preload(&opts->pathspec) < 0)
return error(_("index file corrupt"));
}
errs |= finish_delayed_checkout(&state);
- if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
- read_ref_full("HEAD", 0, rev.hash, NULL);
+ read_ref_full("HEAD", 0, &rev, NULL);
head = lookup_commit_reference_gently(&rev, 1);
errs |= post_checkout_hook(head, head, 0);
int *writeout_error)
{
int ret;
- struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
+ struct lock_file lock_file = LOCK_INIT;
- hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
if (read_cache_preload(NULL) < 0)
return error(_("index file corrupt"));
if (!cache_tree_fully_valid(active_cache_tree))
cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
- if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
if (!opts->force && !opts->quiet)
if (!strcmp(new->name, "HEAD") && !new->path && !opts->force_detach) {
/* Nothing to do. */
} else if (opts->force_detach || !new->path) { /* No longer on any branch. */
- update_ref(msg.buf, "HEAD", new->commit->object.oid.hash, NULL,
- REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
+ update_ref(msg.buf, "HEAD", &new->commit->object.oid, NULL,
+ REF_NO_DEREF, UPDATE_REFS_DIE_ON_ERR);
if (!opts->quiet) {
if (old->path &&
advice_detached_head && !opts->force_detach)
struct object_id rev;
int flag, writeout_error = 0;
memset(&old, 0, sizeof(old));
- old.path = path_to_free = resolve_refdup("HEAD", 0, rev.hash, &flag);
+ old.path = path_to_free = resolve_refdup("HEAD", 0, &rev, &flag);
if (old.path)
old.commit = lookup_commit_reference_gently(&rev, 1);
if (!(flag & REF_ISSYMREF))
setup_branch_path(new);
if (!check_refname_format(new->path, 0) &&
- !read_ref(new->path, branch_rev.hash))
+ !read_ref(new->path, &branch_rev))
oidcpy(rev, &branch_rev);
else
new->path = NULL; /* not an existing branch */
struct object_id rev;
int flag;
- if (!read_ref_full("HEAD", 0, rev.hash, &flag) &&
+ if (!read_ref_full("HEAD", 0, &rev, &flag) &&
(flag & REF_ISSYMREF) && is_null_oid(&rev))
return switch_unborn_to_new_branch(opts);
}
for (r = local_refs; r; r = r->next) {
if (!r->peer_ref)
continue;
- if (ref_transaction_create(t, r->peer_ref->name, r->old_oid.hash,
+ if (ref_transaction_create(t, r->peer_ref->name, &r->old_oid,
0, NULL, &err))
die("%s", err.buf);
}
continue;
if (!has_object_file(&ref->old_oid))
continue;
- update_ref(msg, ref->name, ref->old_oid.hash,
- NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+ update_ref(msg, ref->name, &ref->old_oid, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
}
}
-static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
+static int iterate_ref_map(void *cb_data, struct object_id *oid)
{
struct ref **rm = cb_data;
struct ref *ref = *rm;
if (!ref)
return -1;
- hashcpy(sha1, ref->old_oid.hash);
+ oidcpy(oid, &ref->old_oid);
*rm = ref->next;
return 0;
}
if (create_symref("HEAD", our->name, NULL) < 0)
die(_("unable to update HEAD"));
if (!option_bare) {
- update_ref(msg, "HEAD", our->old_oid.hash, NULL, 0,
+ update_ref(msg, "HEAD", &our->old_oid, NULL, 0,
UPDATE_REFS_DIE_ON_ERR);
install_branch_config(0, head, option_origin, our->name);
}
} else if (our) {
struct commit *c = lookup_commit_reference(&our->old_oid);
/* --branch specifies a non-branch (i.e. tags), detach HEAD */
- update_ref(msg, "HEAD", c->object.oid.hash,
- NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
+ update_ref(msg, "HEAD", &c->object.oid, NULL, REF_NO_DEREF,
+ UPDATE_REFS_DIE_ON_ERR);
} else if (remote) {
/*
* We know remote HEAD points to a non-branch, or
* HEAD points to a branch but we don't know which one.
* Detach HEAD in all these cases.
*/
- update_ref(msg, "HEAD", remote->old_oid.hash,
- NULL, REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
+ update_ref(msg, "HEAD", &remote->old_oid, NULL, REF_NO_DEREF,
+ UPDATE_REFS_DIE_ON_ERR);
}
}
{
struct object_id oid;
char *head;
- struct lock_file *lock_file;
+ struct lock_file lock_file = LOCK_INIT;
struct unpack_trees_options opts;
struct tree *tree;
struct tree_desc t;
if (option_no_checkout)
return 0;
- head = resolve_refdup("HEAD", RESOLVE_REF_READING, oid.hash, NULL);
+ head = resolve_refdup("HEAD", RESOLVE_REF_READING, &oid, NULL);
if (!head) {
warning(_("remote HEAD refers to nonexistent ref, "
"unable to checkout.\n"));
/* We need to be in the new work tree for the checkout */
setup_work_tree();
- lock_file = xcalloc(1, sizeof(struct lock_file));
- hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
+ hold_locked_index(&lock_file, LOCK_DIE_ON_ERROR);
memset(&opts, 0, sizeof opts);
opts.update = 1;
if (unpack_trees(1, &t, &opts) < 0)
die(_("unable to checkout working tree"));
- if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
+ if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("unable to write new index file"));
err |= run_hook_le(NULL, "post-checkout", sha1_to_hex(null_sha1),
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
static int config_commit_verbose = -1; /* unspecified */
static int no_post_rewrite, allow_empty_message;
-static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
+static char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg;
static char *sign_commit;
/*
static enum commit_whence whence;
static int sequencer_in_use;
static int use_editor = 1, include_status = 1;
-static int show_ignored_in_status, have_option_m;
+static int have_option_m;
static struct strbuf message = STRBUF_INIT;
static enum wt_status_format status_format = STATUS_FORMAT_UNSPECIFIED;
refresh_cache_or_die(refresh_flags);
- if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
+ if (write_locked_index(&the_index, &index_lock, 0))
die(_("unable to create temporary index"));
old_index_env = getenv(INDEX_ENVIRONMENT);
if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) {
if (reopen_lock_file(&index_lock) < 0)
die(_("unable to write index file"));
- if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
+ if (write_locked_index(&the_index, &index_lock, 0))
die(_("unable to update temporary index"));
} else
warning(_("Failed to update main cache tree"));
add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
refresh_cache_or_die(refresh_flags);
update_main_cache_tree(WRITE_TREE_SILENT);
- if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
+ if (write_locked_index(&the_index, &index_lock, 0))
die(_("unable to write new_index file"));
commit_style = COMMIT_NORMAL;
ret = get_lock_file_path(&index_lock);
add_remove_files(&partial);
refresh_cache(REFRESH_QUIET);
update_main_cache_tree(WRITE_TREE_SILENT);
- if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))
+ if (write_locked_index(&the_index, &index_lock, 0))
die(_("unable to write new_index file"));
hold_lock_file_for_update(&false_lock,
add_remove_files(&partial);
refresh_cache(REFRESH_QUIET);
- if (write_locked_index(&the_index, &false_lock, CLOSE_LOCK))
+ if (write_locked_index(&the_index, &false_lock, 0))
die(_("unable to write temporary index file"));
discard_cache();
* submodules which were manually staged, which would
* be really confusing.
*/
- int diff_flags = DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG;
+ struct diff_flags flags = DIFF_FLAGS_INIT;
+ flags.override_submodule_config = 1;
if (ignore_submodule_arg &&
!strcmp(ignore_submodule_arg, "all"))
- diff_flags |= DIFF_OPT_IGNORE_SUBMODULES;
- commitable = index_differs_from(parent, diff_flags, 1);
+ flags.ignore_submodules = 1;
+ commitable = index_differs_from(parent, &flags, 1);
}
}
strbuf_release(&committer_ident);
die(_("--author '%s' is not 'Name <email>' and matches no existing author"), name);
}
+static void handle_ignored_arg(struct wt_status *s)
+{
+ if (!ignored_arg)
+ ; /* default already initialized */
+ else if (!strcmp(ignored_arg, "traditional"))
+ s->show_ignored_mode = SHOW_TRADITIONAL_IGNORED;
+ else if (!strcmp(ignored_arg, "no"))
+ s->show_ignored_mode = SHOW_NO_IGNORED;
+ else if (!strcmp(ignored_arg, "matching"))
+ s->show_ignored_mode = SHOW_MATCHING_IGNORED;
+ else
+ die(_("Invalid ignored mode '%s'"), ignored_arg);
+}
static void handle_untracked_files_arg(struct wt_status *s)
{
N_("mode"),
N_("show untracked files, optional modes: all, normal, no. (Default: all)"),
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
- OPT_BOOL(0, "ignored", &show_ignored_in_status,
- N_("show ignored files")),
+ { OPTION_STRING, 0, "ignored", &ignored_arg,
+ N_("mode"),
+ N_("show ignored files, optional modes: traditional, matching, no. (Default: traditional)"),
+ PARSE_OPT_OPTARG, NULL, (intptr_t)"traditional" },
{ OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, N_("when"),
N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"),
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
finalize_deferred_config(&s);
handle_untracked_files_arg(&s);
- if (show_ignored_in_status)
- s.show_ignored_files = 1;
+ handle_ignored_arg(&s);
+
+ if (s.show_ignored_mode == SHOW_MATCHING_IGNORED &&
+ s.show_untracked_files == SHOW_NO_UNTRACKED_FILES)
+ die(_("Unsupported combination of ignored and untracked-files arguments"));
+
parse_pathspec(&s.pathspec, 0,
PATHSPEC_PREFER_FULL,
prefix, argv);
diff_setup_done(&rev.diffopt);
head = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
+ if (!head)
+ die_errno(_("unable to resolve HEAD after creating commit"));
if (!strcmp(head, "HEAD"))
head = _("detached HEAD");
else
transaction = ref_transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, "HEAD", oid.hash,
+ ref_transaction_update(transaction, "HEAD", &oid,
current_head
- ? current_head->object.oid.hash : null_sha1,
+ ? ¤t_head->object.oid : &null_oid,
0, sb.buf, &err) ||
ref_transaction_commit(transaction, &err)) {
rollback_index_files();
#include "builtin.h"
#include "exec_cmd.h"
#include "parse-options.h"
+#include "revision.h"
#include "diff.h"
#include "hashmap.h"
#include "argv-array.h"
#include "run-command.h"
-#define SEEN (1u << 0)
#define MAX_TAGS (FLAG_BITS - 1)
static const char * const describe_usage[] = {
}
/* Is it annotated? */
- if (!peel_ref(path, peeled.hash)) {
+ if (!peel_ref(path, &peeled)) {
is_annotated = !!oidcmp(oid, &peeled);
} else {
oidcpy(&peeled, oid);
}
} else if (dirty) {
static struct lock_file index_lock;
- int fd;
+ struct rev_info revs;
+ struct argv_array args = ARGV_ARRAY_INIT;
+ int fd, result;
read_cache_preload(NULL);
refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED,
if (0 <= fd)
update_index_if_able(&the_index, &index_lock);
- if (!cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1,
- diff_index_args, prefix))
+ init_revisions(&revs, prefix);
+ argv_array_pushv(&args, diff_index_args);
+ if (setup_revisions(args.argc, args.argv, &revs, NULL) != 1)
+ BUG("malformed internal diff-index command line");
+ result = run_diff_index(&revs, 0);
+
+ if (!diff_result_code(&revs.diffopt, result))
suffix = NULL;
else
suffix = dirty;
!oidcmp(old_oid, new_oid) && (old_mode == new_mode))
return;
- if (DIFF_OPT_TST(opt, REVERSE_DIFF)) {
+ if (opt->flags.reverse_diff) {
SWAP(old_mode, new_mode);
SWAP(old_oid, new_oid);
SWAP(old_path, new_path);
static void refresh_index_quietly(void)
{
- struct lock_file *lock_file;
+ struct lock_file lock_file = LOCK_INIT;
int fd;
- lock_file = xcalloc(1, sizeof(struct lock_file));
- fd = hold_locked_index(lock_file, 0);
+ fd = hold_locked_index(&lock_file, 0);
if (fd < 0)
return;
discard_cache();
read_cache();
refresh_cache(REFRESH_QUIET|REFRESH_UNMERGED);
- update_index_if_able(&the_index, lock_file);
+ update_index_if_able(&the_index, &lock_file);
}
static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv)
rev.diffopt.stat_graph_width = -1;
/* Default to let external and textconv be used */
- DIFF_OPT_SET(&rev.diffopt, ALLOW_EXTERNAL);
- DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV);
+ rev.diffopt.flags.allow_external = 1;
+ rev.diffopt.flags.allow_textconv = 1;
if (nongit)
die(_("Not a git repository"));
diff_setup_done(&rev.diffopt);
}
- DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
+ rev.diffopt.flags.recursive = 1;
setup_diff_pager(&rev.diffopt);
if (hold_lock_file_for_update(&lock, buf.buf, 0) < 0 ||
write_locked_index(&wtindex, &lock, COMMIT_LOCK)) {
ret = error("could not write %s", buf.buf);
- rollback_lock_file(&lock);
goto finish;
}
changed_files(&wt_modified, buf.buf, workdir);
if (e->flags & UNINTERESTING)
continue;
- if (dwim_ref(e->name, strlen(e->name), oid.hash, &full_name) != 1)
+ if (dwim_ref(e->name, strlen(e->name), &oid, &full_name) != 1)
continue;
if (refspecs) {
die("revision walk setup failed");
revs.diffopt.format_callback = show_filemodify;
revs.diffopt.format_callback_data = &paths_of_changed_objects;
- DIFF_OPT_SET(&revs.diffopt, RECURSIVE);
+ revs.diffopt.flags.recursive = 1;
while ((commit = get_revision(&revs))) {
if (has_unshown_parent(commit)) {
add_object_array(&commit->object, NULL, &commits);
transaction = ref_transaction_begin(&err);
if (!transaction ||
ref_transaction_update(transaction, ref->name,
- ref->new_oid.hash,
- check_old ? ref->old_oid.hash : NULL,
+ &ref->new_oid,
+ check_old ? &ref->old_oid : NULL,
0, msg, &err))
goto fail;
}
}
-static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
+static int iterate_ref_map(void *cb_data, struct object_id *oid)
{
struct ref **rm = cb_data;
struct ref *ref = *rm;
if (!ref)
return -1; /* end of the list */
*rm = ref->next;
- hashcpy(sha1, ref->old_oid.hash);
+ oidcpy(oid, &ref->old_oid);
return 0;
}
/* get current branch */
current_branch = current_branch_to_free =
- resolve_refdup("HEAD", RESOLVE_REF_READING, head_oid.hash, NULL);
+ resolve_refdup("HEAD", RESOLVE_REF_READING, &head_oid, NULL);
if (!current_branch)
die("No current branch");
if (starts_with(current_branch, "refs/heads/"))
if (verbose)
fprintf(stderr, "Checking HEAD link\n");
- head_points_at = resolve_ref_unsafe("HEAD", 0, head_oid.hash, NULL);
+ head_points_at = resolve_ref_unsafe("HEAD", 0, &head_oid, NULL);
if (!head_points_at) {
errors_found |= ERROR_REFS;
return error("Invalid HEAD");
* store is no longer global and instead is a member of the repository
* object.
*/
+ grep_read_lock();
add_to_alternates_memory(submodule.objectdir);
+ grep_read_unlock();
if (oid) {
struct object *object;
if (fmt_pretty)
get_commit_format(fmt_pretty, rev);
if (default_follow)
- DIFF_OPT_SET(&rev->diffopt, DEFAULT_FOLLOW_RENAMES);
+ rev->diffopt.flags.default_follow_renames = 1;
rev->verbose_header = 1;
- DIFF_OPT_SET(&rev->diffopt, RECURSIVE);
+ rev->diffopt.flags.recursive = 1;
rev->diffopt.stat_width = -1; /* use full terminal width */
rev->diffopt.stat_graph_width = -1; /* respect statGraphWidth config */
rev->abbrev_commit = default_abbrev_commit;
rev->show_root_diff = default_show_root;
rev->subject_prefix = fmt_patch_subject_prefix;
rev->show_signature = default_show_signature;
- DIFF_OPT_SET(&rev->diffopt, ALLOW_TEXTCONV);
+ rev->diffopt.flags.allow_textconv = 1;
if (default_date_mode)
parse_date_format(default_date_mode, &rev->date_mode);
- rev->diffopt.touched_flags = 0;
}
static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,
init_display_notes(&rev->notes_opt);
if (rev->diffopt.pickaxe || rev->diffopt.filter ||
- DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES))
+ rev->diffopt.flags.follow_renames)
rev->always_show_header = 0;
if (source)
fclose(rev->diffopt.file);
if (rev->diffopt.output_format & DIFF_FORMAT_CHECKDIFF &&
- DIFF_OPT_TST(&rev->diffopt, CHECK_FAILED)) {
+ rev->diffopt.flags.check_failed) {
return 02;
}
return diff_result_code(&rev->diffopt, 0);
unsigned long size;
fflush(rev->diffopt.file);
- if (!DIFF_OPT_TOUCHED(&rev->diffopt, ALLOW_TEXTCONV) ||
- !DIFF_OPT_TST(&rev->diffopt, ALLOW_TEXTCONV))
+ if (!rev->diffopt.flags.textconv_set_via_cmdline ||
+ !rev->diffopt.flags.allow_textconv)
return stream_blob_to_fd(1, oid, NULL, 0);
if (get_oid_with_context(obj_name, GET_OID_RECORD_PATH,
static void log_setup_revisions_tweak(struct rev_info *rev,
struct setup_revision_opt *opt)
{
- if (DIFF_OPT_TST(&rev->diffopt, DEFAULT_FOLLOW_RENAMES) &&
+ if (rev->diffopt.flags.default_follow_renames &&
rev->prune_data.nr == 1)
- DIFF_OPT_SET(&rev->diffopt, FOLLOW_RENAMES);
+ rev->diffopt.flags.follow_renames = 1;
/* Turn --cc/-c into -p --cc/-c when -p was not given */
if (!rev->diffopt.output_format && rev->combine_merges)
return NULL;
ref = rev->cmdline.rev[positive].name;
tip_oid = &rev->cmdline.rev[positive].item->oid;
- if (dwim_ref(ref, strlen(ref), branch_oid.hash, &full_ref) &&
+ if (dwim_ref(ref, strlen(ref), &branch_oid, &full_ref) &&
skip_prefix(full_ref, "refs/heads/", &v) &&
!oidcmp(tip_oid, &branch_oid))
branch = xstrdup(v);
return;
diff_setup(&diffopt);
- DIFF_OPT_SET(&diffopt, RECURSIVE);
+ diffopt.flags.recursive = 1;
diff_setup_done(&diffopt);
oidcpy(&bases->base_commit, &base->object.oid);
rev.verbose_header = 1;
rev.diff = 1;
rev.max_parents = 1;
- DIFF_OPT_SET(&rev.diffopt, RECURSIVE);
+ rev.diffopt.flags.recursive = 1;
rev.subject_prefix = fmt_patch_subject_prefix;
memset(&s_r_opt, 0, sizeof(s_r_opt));
s_r_opt.def = "HEAD";
rev.zero_commit = zero_commit;
- if (!DIFF_OPT_TST(&rev.diffopt, TEXT) && !no_binary_diff)
- DIFF_OPT_SET(&rev.diffopt, BINARY);
+ if (!rev.diffopt.flags.text && !no_binary_diff)
+ rev.diffopt.flags.binary = 1;
if (rev.show_notes)
init_display_notes(&rev.notes_opt);
struct commit_list *bases;
int i, ret = 0;
- switch (dwim_ref(argv[0], strlen(argv[0]), oid.hash, &refname)) {
+ switch (dwim_ref(argv[0], strlen(argv[0]), &oid, &refname)) {
case 0:
die("No such ref: '%s'", argv[0]);
case 1:
*/
#include "git-compat-util.h"
#include "builtin.h"
+#include "diff.h"
static const char builtin_merge_ours_usage[] =
"git merge-ours <base>... -- HEAD <remote>...";
-static const char *diff_index_args[] = {
- "diff-index", "--quiet", "--cached", "HEAD", "--", NULL
-};
-#define NARGS (ARRAY_SIZE(diff_index_args) - 1)
-
int cmd_merge_ours(int argc, const char **argv, const char *prefix)
{
if (argc == 2 && !strcmp(argv[1], "-h"))
usage(builtin_merge_ours_usage);
/*
- * We need to exit with 2 if the index does not match our HEAD tree,
- * because the current index is what we will be committing as the
- * merge result.
+ * The contents of the current index becomes the tree we
+ * commit. The index must match HEAD, or this merge cannot go
+ * through.
*/
- if (cmd_diff_index(NARGS, diff_index_args, prefix))
+ if (read_cache() < 0)
+ die_errno("read_cache failed");
+ if (index_differs_from("HEAD", NULL, 0))
exit(2);
exit(0);
}
printf(_("No merge message -- not updating HEAD\n"));
else {
const char *argv_gc_auto[] = { "gc", "--auto", NULL };
- update_ref(reflog_message.buf, "HEAD",
- new_head->hash, head->hash, 0,
- UPDATE_REFS_DIE_ON_ERR);
+ update_ref(reflog_message.buf, "HEAD", new_head, head,
+ 0, UPDATE_REFS_DIE_ON_ERR);
/*
* We ignore errors in 'gc --auto', since the
* user should see them.
if (!remote_head)
die(_("'%s' does not point to a commit"), remote);
- if (dwim_ref(remote, strlen(remote), branch_head.hash, &found_ref) > 0) {
+ if (dwim_ref(remote, strlen(remote), &branch_head, &found_ref) > 0) {
if (starts_with(found_ref, "refs/heads/")) {
strbuf_addf(msg, "%s\t\tbranch '%s' of .\n",
oid_to_hex(&branch_head), remote);
* Check if we are _not_ on a detached HEAD, i.e. if there is a
* current branch.
*/
- branch = branch_to_free = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+ branch = branch_to_free = resolve_refdup("HEAD", 0, &head_oid, NULL);
if (branch)
skip_prefix(branch, "refs/heads/", &branch);
if (!branch || is_null_oid(&head_oid))
die(_("Can merge only exactly one commit into empty head"));
remote_head_oid = &remoteheads->item->object.oid;
read_empty(remote_head_oid->hash, 0);
- update_ref("initial pull", "HEAD", remote_head_oid->hash,
- NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+ update_ref("initial pull", "HEAD", remote_head_oid, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
goto done;
}
free(list);
}
- update_ref("updating ORIG_HEAD", "ORIG_HEAD", head_commit->object.oid.hash,
- NULL, 0, UPDATE_REFS_DIE_ON_ERR);
+ update_ref("updating ORIG_HEAD", "ORIG_HEAD",
+ &head_commit->object.oid, NULL, 0, UPDATE_REFS_DIE_ON_ERR);
if (remoteheads && !common) {
/* No common ancestors found. */
if (delete_ref(NULL, "NOTES_MERGE_PARTIAL", NULL, 0))
ret += error(_("failed to delete ref NOTES_MERGE_PARTIAL"));
- if (delete_ref(NULL, "NOTES_MERGE_REF", NULL, REF_NODEREF))
+ if (delete_ref(NULL, "NOTES_MERGE_REF", NULL, REF_NO_DEREF))
ret += error(_("failed to delete ref NOTES_MERGE_REF"));
if (notes_merge_abort(o))
ret += error(_("failed to remove 'git notes merge' worktree"));
init_notes(t, "NOTES_MERGE_PARTIAL", combine_notes_overwrite, 0);
o->local_ref = local_ref_to_free =
- resolve_refdup("NOTES_MERGE_REF", 0, oid.hash, NULL);
+ resolve_refdup("NOTES_MERGE_REF", 0, &oid, NULL);
if (!o->local_ref)
die(_("failed to resolve NOTES_MERGE_REF"));
format_commit_message(partial, "%s", &msg, &pretty_ctx);
strbuf_trim(&msg);
strbuf_insert(&msg, 0, "notes: ", 7);
- update_ref(msg.buf, o->local_ref, oid.hash,
- is_null_oid(&parent_oid) ? NULL : parent_oid.hash,
+ update_ref(msg.buf, o->local_ref, &oid,
+ is_null_oid(&parent_oid) ? NULL : &parent_oid,
0, UPDATE_REFS_DIE_ON_ERR);
free_notes(t);
if (result >= 0) /* Merge resulted (trivially) in result_oid */
/* Update default notes ref with new commit */
- update_ref(msg.buf, default_notes_ref(), result_oid.hash, NULL,
- 0, UPDATE_REFS_DIE_ON_ERR);
+ update_ref(msg.buf, default_notes_ref(), &result_oid, NULL, 0,
+ UPDATE_REFS_DIE_ON_ERR);
else { /* Merge has unresolved conflicts */
const struct worktree *wt;
/* Update .git/NOTES_MERGE_PARTIAL with partial merge result */
- update_ref(msg.buf, "NOTES_MERGE_PARTIAL", result_oid.hash, NULL,
+ update_ref(msg.buf, "NOTES_MERGE_PARTIAL", &result_oid, NULL,
0, UPDATE_REFS_DIE_ON_ERR);
/* Store ref-to-be-updated into .git/NOTES_MERGE_REF */
wt = find_shared_symref("NOTES_MERGE_REF", default_notes_ref());
}
static unsigned long write_large_blob_data(struct git_istream *st, struct sha1file *f,
- const unsigned char *sha1)
+ const struct object_id *oid)
{
git_zstream stream;
unsigned char ibuf[1024 * 16];
int zret = Z_OK;
readlen = read_istream(st, ibuf, sizeof(ibuf));
if (readlen == -1)
- die(_("unable to read %s"), sha1_to_hex(sha1));
+ die(_("unable to read %s"), oid_to_hex(oid));
stream.next_in = ibuf;
stream.avail_in = readlen;
sha1write(f, header, hdrlen);
}
if (st) {
- datalen = write_large_blob_data(st, f, entry->idx.oid.hash);
+ datalen = write_large_blob_data(st, f, &entry->idx.oid);
close_istream(st);
} else {
sha1write(f, buf, datalen);
static int mark_tagged(const char *path, const struct object_id *oid, int flag,
void *cb_data)
{
- unsigned char peeled[20];
+ struct object_id peeled;
struct object_entry *entry = packlist_find(&to_pack, oid->hash, NULL);
if (entry)
entry->tagged = 1;
- if (!peel_ref(path, peeled)) {
- entry = packlist_find(&to_pack, peeled, NULL);
+ if (!peel_ref(path, &peeled)) {
+ entry = packlist_find(&to_pack, peeled.hash, NULL);
if (entry)
entry->tagged = 1;
}
write_order = compute_write_order();
do {
- unsigned char sha1[20];
+ struct object_id oid;
char *pack_tmp_name = NULL;
if (pack_to_stdout)
* If so, rewrite it like in fast-import
*/
if (pack_to_stdout) {
- sha1close(f, sha1, CSUM_CLOSE);
+ sha1close(f, oid.hash, CSUM_CLOSE);
} else if (nr_written == nr_remaining) {
- sha1close(f, sha1, CSUM_FSYNC);
+ sha1close(f, oid.hash, CSUM_FSYNC);
} else {
- int fd = sha1close(f, sha1, 0);
- fixup_pack_header_footer(fd, sha1, pack_tmp_name,
- nr_written, sha1, offset);
+ int fd = sha1close(f, oid.hash, 0);
+ fixup_pack_header_footer(fd, oid.hash, pack_tmp_name,
+ nr_written, oid.hash, offset);
close(fd);
if (write_bitmap_index) {
warning(_(no_split_warning));
strbuf_addf(&tmpname, "%s-", base_name);
if (write_bitmap_index) {
- bitmap_writer_set_checksum(sha1);
+ bitmap_writer_set_checksum(oid.hash);
bitmap_writer_build_type_index(written_list, nr_written);
}
finish_tmp_packfile(&tmpname, pack_tmp_name,
written_list, nr_written,
- &pack_idx_opts, sha1);
+ &pack_idx_opts, oid.hash);
if (write_bitmap_index) {
- strbuf_addf(&tmpname, "%s.bitmap", sha1_to_hex(sha1));
+ strbuf_addf(&tmpname, "%s.bitmap", oid_to_hex(&oid));
stop_progress(&progress_state);
strbuf_release(&tmpname);
free(pack_tmp_name);
- puts(sha1_to_hex(sha1));
+ puts(oid_to_hex(&oid));
}
/* mark written objects as written to previous pack */
* found the item, since that saves us from having to look it up again a
* few lines later when we want to add the new entry.
*/
-static int have_duplicate_entry(const unsigned char *sha1,
+static int have_duplicate_entry(const struct object_id *oid,
int exclude,
uint32_t *index_pos)
{
struct object_entry *entry;
- entry = packlist_find(&to_pack, sha1, index_pos);
+ entry = packlist_find(&to_pack, oid->hash, index_pos);
if (!entry)
return 0;
* function finds if there is any pack that has the object and returns the pack
* and its offset in these variables.
*/
-static int want_object_in_pack(const unsigned char *sha1,
+static int want_object_in_pack(const struct object_id *oid,
int exclude,
struct packed_git **found_pack,
off_t *found_offset)
struct mru_entry *entry;
int want;
- if (!exclude && local && has_loose_object_nonlocal(sha1))
+ if (!exclude && local && has_loose_object_nonlocal(oid->hash))
return 0;
/*
if (p == *found_pack)
offset = *found_offset;
else
- offset = find_pack_entry_one(sha1, p);
+ offset = find_pack_entry_one(oid->hash, p);
if (offset) {
if (!*found_pack) {
return 1;
}
-static void create_object_entry(const unsigned char *sha1,
+static void create_object_entry(const struct object_id *oid,
enum object_type type,
uint32_t hash,
int exclude,
{
struct object_entry *entry;
- entry = packlist_alloc(&to_pack, sha1, index_pos);
+ entry = packlist_alloc(&to_pack, oid->hash, index_pos);
entry->hash = hash;
if (type)
entry->type = type;
"disabling bitmap writing, as some objects are not being packed"
);
-static int add_object_entry(const unsigned char *sha1, enum object_type type,
+static int add_object_entry(const struct object_id *oid, enum object_type type,
const char *name, int exclude)
{
struct packed_git *found_pack = NULL;
off_t found_offset = 0;
uint32_t index_pos;
- if (have_duplicate_entry(sha1, exclude, &index_pos))
+ if (have_duplicate_entry(oid, exclude, &index_pos))
return 0;
- if (!want_object_in_pack(sha1, exclude, &found_pack, &found_offset)) {
+ if (!want_object_in_pack(oid, exclude, &found_pack, &found_offset)) {
/* The pack is missing an object, so it will not have closure */
if (write_bitmap_index) {
warning(_(no_closure_warning));
return 0;
}
- create_object_entry(sha1, type, pack_name_hash(name),
+ create_object_entry(oid, type, pack_name_hash(name),
exclude, name && no_try_delta(name),
index_pos, found_pack, found_offset);
return 1;
}
-static int add_object_entry_from_bitmap(const unsigned char *sha1,
+static int add_object_entry_from_bitmap(const struct object_id *oid,
enum object_type type,
int flags, uint32_t name_hash,
struct packed_git *pack, off_t offset)
{
uint32_t index_pos;
- if (have_duplicate_entry(sha1, 0, &index_pos))
+ if (have_duplicate_entry(oid, 0, &index_pos))
return 0;
- if (!want_object_in_pack(sha1, 0, &pack, &offset))
+ if (!want_object_in_pack(oid, 0, &pack, &offset))
return 0;
- create_object_entry(sha1, type, name_hash, 0, 0, index_pos, pack, offset);
+ create_object_entry(oid, type, name_hash, 0, 0, index_pos, pack, offset);
display_progress(progress_state, nr_result);
return 1;
}
struct pbase_tree_cache {
- unsigned char sha1[20];
+ struct object_id oid;
int ref;
int temporary;
void *tree_data;
};
static struct pbase_tree_cache *(pbase_tree_cache[256]);
-static int pbase_tree_cache_ix(const unsigned char *sha1)
+static int pbase_tree_cache_ix(const struct object_id *oid)
{
- return sha1[0] % ARRAY_SIZE(pbase_tree_cache);
+ return oid->hash[0] % ARRAY_SIZE(pbase_tree_cache);
}
static int pbase_tree_cache_ix_incr(int ix)
{
struct pbase_tree_cache pcache;
} *pbase_tree;
-static struct pbase_tree_cache *pbase_tree_get(const unsigned char *sha1)
+static struct pbase_tree_cache *pbase_tree_get(const struct object_id *oid)
{
struct pbase_tree_cache *ent, *nent;
void *data;
unsigned long size;
enum object_type type;
int neigh;
- int my_ix = pbase_tree_cache_ix(sha1);
+ int my_ix = pbase_tree_cache_ix(oid);
int available_ix = -1;
/* pbase-tree-cache acts as a limited hashtable.
*/
for (neigh = 0; neigh < 8; neigh++) {
ent = pbase_tree_cache[my_ix];
- if (ent && !hashcmp(ent->sha1, sha1)) {
+ if (ent && !oidcmp(&ent->oid, oid)) {
ent->ref++;
return ent;
}
/* Did not find one. Either we got a bogus request or
* we need to read and perhaps cache.
*/
- data = read_sha1_file(sha1, &type, &size);
+ data = read_sha1_file(oid->hash, &type, &size);
if (!data)
return NULL;
if (type != OBJ_TREE) {
free(ent->tree_data);
nent = ent;
}
- hashcpy(nent->sha1, sha1);
+ oidcpy(&nent->oid, oid);
nent->tree_data = data;
nent->tree_size = size;
nent->ref = 1;
if (cmp < 0)
return;
if (name[cmplen] != '/') {
- add_object_entry(entry.oid->hash,
+ add_object_entry(entry.oid,
object_type(entry.mode),
fullname, 1);
return;
const char *down = name+cmplen+1;
int downlen = name_cmp_len(down);
- tree = pbase_tree_get(entry.oid->hash);
+ tree = pbase_tree_get(entry.oid);
if (!tree)
return;
init_tree_desc(&sub, tree->tree_data, tree->tree_size);
cmplen = name_cmp_len(name);
for (it = pbase_tree; it; it = it->next) {
if (cmplen == 0) {
- add_object_entry(it->pcache.sha1, OBJ_TREE, NULL, 1);
+ add_object_entry(&it->pcache.oid, OBJ_TREE, NULL, 1);
}
else {
struct tree_desc tree;
}
}
-static void add_preferred_base(unsigned char *sha1)
+static void add_preferred_base(struct object_id *oid)
{
struct pbase_tree *it;
void *data;
unsigned long size;
- unsigned char tree_sha1[20];
+ struct object_id tree_oid;
if (window <= num_preferred_base++)
return;
- data = read_object_with_reference(sha1, tree_type, &size, tree_sha1);
+ data = read_object_with_reference(oid->hash, tree_type, &size, tree_oid.hash);
if (!data)
return;
for (it = pbase_tree; it; it = it->next) {
- if (!hashcmp(it->pcache.sha1, tree_sha1)) {
+ if (!oidcmp(&it->pcache.oid, &tree_oid)) {
free(data);
return;
}
it->next = pbase_tree;
pbase_tree = it;
- hashcpy(it->pcache.sha1, tree_sha1);
+ oidcpy(&it->pcache.oid, &tree_oid);
it->pcache.tree_data = data;
it->pcache.tree_size = size;
}
die("unable to pack objects reachable from tag %s",
oid_to_hex(oid));
- add_object_entry(tag->object.oid.hash, OBJ_TAG, NULL, 0);
+ add_object_entry(&tag->object.oid, OBJ_TAG, NULL, 0);
if (tag->tagged->type != OBJ_TAG)
return;
struct object_id peeled;
if (starts_with(path, "refs/tags/") && /* is a tag? */
- !peel_ref(path, peeled.hash) && /* peelable? */
+ !peel_ref(path, &peeled) && /* peelable? */
packlist_find(&to_pack, peeled.hash, NULL)) /* object packed? */
add_tag_chain(oid);
return 0;
static void read_object_list_from_stdin(void)
{
- char line[40 + 1 + PATH_MAX + 2];
- unsigned char sha1[20];
+ char line[GIT_MAX_HEXSZ + 1 + PATH_MAX + 2];
+ struct object_id oid;
+ const char *p;
for (;;) {
if (!fgets(line, sizeof(line), stdin)) {
continue;
}
if (line[0] == '-') {
- if (get_sha1_hex(line+1, sha1))
- die("expected edge sha1, got garbage:\n %s",
+ if (get_oid_hex(line+1, &oid))
+ die("expected edge object ID, got garbage:\n %s",
line);
- add_preferred_base(sha1);
+ add_preferred_base(&oid);
continue;
}
- if (get_sha1_hex(line, sha1))
- die("expected sha1, got garbage:\n %s", line);
+ if (parse_oid_hex(line, &oid, &p))
+ die("expected object ID, got garbage:\n %s", line);
- add_preferred_base_object(line+41);
- add_object_entry(sha1, 0, line+41, 0);
+ add_preferred_base_object(p + 1);
+ add_object_entry(&oid, 0, p + 1, 0);
}
}
static void show_commit(struct commit *commit, void *data)
{
- add_object_entry(commit->object.oid.hash, OBJ_COMMIT, NULL, 0);
+ add_object_entry(&commit->object.oid, OBJ_COMMIT, NULL, 0);
commit->object.flags |= OBJECT_ADDED;
if (write_bitmap_index)
static void show_object(struct object *obj, const char *name, void *data)
{
add_preferred_base_object(name);
- add_object_entry(obj->oid.hash, obj->type, name, 0);
+ add_object_entry(&obj->oid, obj->type, name, 0);
obj->flags |= OBJECT_ADDED;
}
static void show_edge(struct commit *commit)
{
- add_preferred_base(commit->object.oid.hash);
+ add_preferred_base(&commit->object.oid);
}
struct in_pack_object {
memset(&in_pack, 0, sizeof(in_pack));
for (p = packed_git; p; p = p->next) {
- const unsigned char *sha1;
+ struct object_id oid;
struct object *o;
if (!p->pack_local || p->pack_keep)
in_pack.alloc);
for (i = 0; i < p->num_objects; i++) {
- sha1 = nth_packed_object_sha1(p, i);
- o = lookup_unknown_object(sha1);
+ nth_packed_object_oid(&oid, p, i);
+ o = lookup_unknown_object(oid.hash);
if (!(o->flags & OBJECT_ADDED))
mark_in_pack_object(o, p, &in_pack);
o->flags |= OBJECT_ADDED;
QSORT(in_pack.array, in_pack.nr, ofscmp);
for (i = 0; i < in_pack.nr; i++) {
struct object *o = in_pack.array[i].object;
- add_object_entry(o->oid.hash, o->type, "", 0);
+ add_object_entry(&o->oid, o->type, "", 0);
}
}
free(in_pack.array);
return 0;
}
- add_object_entry(oid->hash, type, "", 0);
+ add_object_entry(oid, type, "", 0);
return 0;
}
NULL, NULL, NULL);
}
-static int has_sha1_pack_kept_or_nonlocal(const unsigned char *sha1)
+static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid)
{
static struct packed_git *last_found = (void *)1;
struct packed_git *p;
while (p) {
if ((!p->pack_local || p->pack_keep) &&
- find_pack_entry_one(sha1, p)) {
+ find_pack_entry_one(oid->hash, p)) {
last_found = p;
return 1;
}
for (i = 0; i < p->num_objects; i++) {
nth_packed_object_oid(&oid, p, i);
if (!packlist_find(&to_pack, oid.hash, NULL) &&
- !has_sha1_pack_kept_or_nonlocal(oid.hash) &&
+ !has_sha1_pack_kept_or_nonlocal(&oid) &&
!loosened_object_can_be_discarded(&oid, p->mtime))
if (force_object_loose(oid.hash, p->mtime))
die("unable to force loose object");
static enum rebase_type opt_rebase = -1;
static char *opt_diffstat;
static char *opt_log;
+static char *opt_signoff;
static char *opt_squash;
static char *opt_commit;
static char *opt_edit;
OPT_PASSTHRU(0, "log", &opt_log, N_("n"),
N_("add (at most <n>) entries from shortlog to merge commit message"),
PARSE_OPT_OPTARG),
+ OPT_PASSTHRU(0, "signoff", &opt_signoff, NULL,
+ N_("add Signed-off-by:"),
+ PARSE_OPT_OPTARG),
OPT_PASSTHRU(0, "squash", &opt_squash, NULL,
N_("create a single commit instead of doing a merge"),
PARSE_OPT_NOARG),
if (checkout_fast_forward(&empty_tree_oid, merge_head, 0))
return 1;
- if (update_ref("initial pull", "HEAD", merge_head->hash, curr_head->hash, 0, UPDATE_REFS_DIE_ON_ERR))
+ if (update_ref("initial pull", "HEAD", merge_head, curr_head, 0, UPDATE_REFS_DIE_ON_ERR))
return 1;
return 0;
argv_array_push(&args, opt_diffstat);
if (opt_log)
argv_array_push(&args, opt_log);
+ if (opt_signoff)
+ argv_array_push(&args, opt_signoff);
if (opt_squash)
argv_array_push(&args, opt_squash);
if (opt_commit)
static int refspec_nr;
static int refspec_alloc;
+static struct string_list push_options_config = STRING_LIST_INIT_DUP;
+
static void add_refspec(const char *ref)
{
refspec_nr++;
int val = git_config_bool(k, v) ?
RECURSE_SUBMODULES_ON_DEMAND : RECURSE_SUBMODULES_OFF;
recurse_submodules = val;
+ } else if (!strcmp(k, "push.pushoption")) {
+ if (!v)
+ return config_error_nonbool(k);
+ else
+ if (!*v)
+ string_list_clear(&push_options_config, 0);
+ else
+ string_list_append(&push_options_config, v);
+ return 0;
}
return git_default_config(k, v, NULL);
int push_cert = -1;
int rc;
const char *repo = NULL; /* default repository */
- struct string_list push_options = STRING_LIST_INIT_DUP;
+ struct string_list push_options_cmdline = STRING_LIST_INIT_DUP;
+ struct string_list *push_options;
const struct string_list_item *item;
struct option options[] = {
0, "signed", &push_cert, "yes|no|if-asked", N_("GPG sign the push"),
PARSE_OPT_OPTARG, option_parse_push_signed },
OPT_BIT(0, "atomic", &flags, N_("request atomic transaction on remote side"), TRANSPORT_PUSH_ATOMIC),
- OPT_STRING_LIST('o', "push-option", &push_options, N_("server-specific"), N_("option to transmit")),
+ OPT_STRING_LIST('o', "push-option", &push_options_cmdline, N_("server-specific"), N_("option to transmit")),
OPT_SET_INT('4', "ipv4", &family, N_("use IPv4 addresses only"),
TRANSPORT_FAMILY_IPV4),
OPT_SET_INT('6', "ipv6", &family, N_("use IPv6 addresses only"),
packet_trace_identity("push");
git_config(git_push_config, &flags);
argc = parse_options(argc, argv, prefix, options, push_usage, 0);
+ push_options = (push_options_cmdline.nr
+ ? &push_options_cmdline
+ : &push_options_config);
set_push_cert_flags(&flags, push_cert);
if (deleterefs && (tags || (flags & (TRANSPORT_PUSH_ALL | TRANSPORT_PUSH_MIRROR))))
set_refspecs(argv + 1, argc - 1, repo);
}
- for_each_string_list_item(item, &push_options)
+ for_each_string_list_item(item, push_options)
if (strchr(item->string, '\n'))
die(_("push options must not have new line characters"));
- rc = do_push(repo, flags, &push_options);
- string_list_clear(&push_options, 0);
+ rc = do_push(repo, flags, push_options);
+ string_list_clear(&push_options_cmdline, 0);
+ string_list_clear(&push_options_config, 0);
if (rc == -1)
usage_with_options(push_usage, options);
else
rp_error("%s", _(refuse_unconfigured_deny_delete_current_msg));
}
-static int command_singleton_iterator(void *cb_data, unsigned char sha1[20]);
+static int command_singleton_iterator(void *cb_data, struct object_id *oid);
static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
{
static struct lock_file shallow_lock;
}
if (ref_transaction_delete(transaction,
namespaced_name,
- old_oid ? old_oid->hash : NULL,
+ old_oid,
0, "push", &err)) {
rp_error("%s", err.buf);
strbuf_release(&err);
if (ref_transaction_update(transaction,
namespaced_name,
- new_oid->hash, old_oid->hash,
+ new_oid, old_oid,
0, "push",
&err)) {
rp_error("%s", err.buf);
string_list_clear(&ref_list, 0);
}
-static int command_singleton_iterator(void *cb_data, unsigned char sha1[20])
+static int command_singleton_iterator(void *cb_data, struct object_id *oid)
{
struct command **cmd_list = cb_data;
struct command *cmd = *cmd_list;
if (!cmd || is_null_oid(&cmd->new_oid))
return -1; /* end of list */
*cmd_list = NULL; /* this returns only one */
- hashcpy(sha1, cmd->new_oid.hash);
+ oidcpy(oid, &cmd->new_oid);
return 0;
}
struct shallow_info *si;
};
-static int iterate_receive_command_list(void *cb_data, unsigned char sha1[20])
+static int iterate_receive_command_list(void *cb_data, struct object_id *oid)
{
struct iterate_data *data = cb_data;
struct command **cmd_list = &data->cmds;
/* to be checked in update_shallow_ref() */
continue;
if (!is_null_oid(&cmd->new_oid) && !cmd->skip_update) {
- hashcpy(sha1, cmd->new_oid.hash);
+ oidcpy(oid, &cmd->new_oid);
*cmd_list = cmd->next;
return 0;
}
};
struct collected_reflog {
- unsigned char sha1[20];
+ struct object_id oid;
char reflog[FLEX_ARRAY];
};
struct collect_reflog_cb *cb = cb_data;
FLEX_ALLOC_STR(e, reflog, ref);
- hashcpy(e->sha1, oid->hash);
+ oidcpy(&e->oid, oid);
ALLOC_GROW(cb->e, cb->nr + 1, cb->alloc);
cb->e[cb->nr++] = e;
return 0;
for (i = 0; i < collected.nr; i++) {
struct collected_reflog *e = collected.e[i];
set_reflog_expiry_param(&cb.cmd, explicit_expiry, e->reflog);
- status |= reflog_expire(e->reflog, e->sha1, flags,
+ status |= reflog_expire(e->reflog, &e->oid, flags,
reflog_expiry_prepare,
should_expire_reflog_ent,
reflog_expiry_cleanup,
for (; i < argc; i++) {
char *ref;
- unsigned char sha1[20];
- if (!dwim_log(argv[i], strlen(argv[i]), sha1, &ref)) {
+ struct object_id oid;
+ if (!dwim_log(argv[i], strlen(argv[i]), &oid, &ref)) {
status |= error("%s points nowhere!", argv[i]);
continue;
}
set_reflog_expiry_param(&cb.cmd, explicit_expiry, ref);
- status |= reflog_expire(ref, sha1, flags,
+ status |= reflog_expire(ref, &oid, flags,
reflog_expiry_prepare,
should_expire_reflog_ent,
reflog_expiry_cleanup,
for ( ; i < argc; i++) {
const char *spec = strstr(argv[i], "@{");
- unsigned char sha1[20];
+ struct object_id oid;
char *ep, *ref;
int recno;
continue;
}
- if (!dwim_log(argv[i], spec - argv[i], sha1, &ref)) {
+ if (!dwim_log(argv[i], spec - argv[i], &oid, &ref)) {
status |= error("no reflog for '%s'", argv[i]);
continue;
}
cb.cmd.expire_total = 0;
}
- status |= reflog_expire(ref, sha1, flags,
+ status |= reflog_expire(ref, &oid, flags,
reflog_expiry_prepare,
should_expire_reflog_ent,
reflog_expiry_cleanup,
item = string_list_append(rename->remote_branches, xstrdup(refname));
symref = resolve_ref_unsafe(refname, RESOLVE_REF_READING,
NULL, &flag);
- if (flag & REF_ISSYMREF)
+ if (symref && (flag & REF_ISSYMREF))
item->util = xstrdup(symref);
else
item->util = NULL;
int flag = 0;
struct object_id oid;
- read_ref_full(item->string, RESOLVE_REF_READING, oid.hash, &flag);
+ read_ref_full(item->string, RESOLVE_REF_READING, &oid, &flag);
if (!(flag & REF_ISSYMREF))
continue;
- if (delete_ref(NULL, item->string, NULL, REF_NODEREF))
+ if (delete_ref(NULL, item->string, NULL, REF_NO_DEREF))
die(_("deleting '%s' failed"), item->string);
}
for (i = 0; i < remote_branches.nr; i++) {
strbuf_release(&buf);
if (!result)
- result = delete_refs("remote: remove", &branches, REF_NODEREF);
+ result = delete_refs("remote: remove", &branches, REF_NO_DEREF);
string_list_clear(&branches, 0);
if (skipped.nr) {
head_name = xstrdup(states.heads.items[0].string);
free_remote_ref_states(&states);
} else if (opt_d && !opt_a && argc == 1) {
- if (delete_ref(NULL, buf.buf, NULL, REF_NODEREF))
+ if (delete_ref(NULL, buf.buf, NULL, REF_NO_DEREF))
result |= error(_("Could not delete %s"), buf.buf);
} else
usage_with_options(builtin_remote_sethead_usage, options);
strbuf_addstr(&ref, oid_to_hex(&oid));
full_hex = ref.buf + base_len;
- if (read_ref(ref.buf, oid.hash)) {
+ if (read_ref(ref.buf, &oid)) {
error("replace ref '%s' not found.", full_hex);
had_error = 1;
continue;
static int delete_replace_ref(const char *name, const char *ref,
const struct object_id *oid)
{
- if (delete_ref(NULL, ref, oid->hash, 0))
+ if (delete_ref(NULL, ref, oid, 0))
return 1;
printf("Deleted replace ref '%s'\n", name);
return 0;
if (check_refname_format(ref->buf, 0))
die("'%s' is not a valid ref name.", ref->buf);
- if (read_ref(ref->buf, prev->hash))
+ if (read_ref(ref->buf, prev))
oidclr(prev);
else if (!force)
die("replace ref '%s' already exists", ref->buf);
transaction = ref_transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, ref.buf, repl->hash, prev.hash,
+ ref_transaction_update(transaction, ref.buf, repl, &prev,
0, NULL, &err) ||
ref_transaction_commit(transaction, &err))
die("%s", err.buf);
opt.output_format = DIFF_FORMAT_CALLBACK;
opt.format_callback = update_index_from_diff;
opt.format_callback_data = &intent_to_add;
- opt.flags |= DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG;
+ opt.flags.override_submodule_config = 1;
if (do_diff_cache(tree_oid, &opt))
return 1;
if (!get_oid("HEAD", &oid_orig)) {
orig = &oid_orig;
set_reflog_message(&msg, "updating ORIG_HEAD", NULL);
- update_ref_oid(msg.buf, "ORIG_HEAD", orig, old_orig, 0,
+ update_ref(msg.buf, "ORIG_HEAD", orig, old_orig, 0,
UPDATE_REFS_MSG_ON_ERR);
} else if (old_orig)
- delete_ref(NULL, "ORIG_HEAD", old_orig->hash, 0);
+ delete_ref(NULL, "ORIG_HEAD", old_orig, 0);
set_reflog_message(&msg, "updating HEAD", rev);
- update_ref_status = update_ref_oid(msg.buf, "HEAD", oid, orig, 0,
+ update_ref_status = update_ref(msg.buf, "HEAD", oid, orig, 0,
UPDATE_REFS_MSG_ON_ERR);
strbuf_release(&msg);
return update_ref_status;
}
static int show_object_fast(
- const unsigned char *sha1,
+ const struct object_id *oid,
enum object_type type,
int exclude,
uint32_t name_hash,
struct packed_git *found_pack,
off_t found_offset)
{
- fprintf(stdout, "%s\n", sha1_to_hex(sha1));
+ fprintf(stdout, "%s\n", oid_to_hex(oid));
return 1;
}
if (revs.bisect)
bisect_list = 1;
- if (DIFF_OPT_TST(&revs.diffopt, QUICK))
+ if (revs.diffopt.flags.quick)
info.flags |= REV_LIST_QUIET;
for (i = 1 ; i < argc; i++) {
const char *arg = argv[i];
if (bisect_list) {
int reaches = reaches, all = all;
- revs.commits = find_bisection(revs.commits, &reaches, &all,
- bisect_find_all);
+ find_bisection(&revs.commits, &reaches, &all, bisect_find_all);
if (bisect_show_vars)
return show_bisect_vars(&info, reaches, all);
struct object_id discard;
char *full;
- switch (dwim_ref(name, strlen(name), discard.hash, &full)) {
+ switch (dwim_ref(name, strlen(name), &discard, &full)) {
case 0:
/*
* Not found -- not a ref. We could
static const char *fake_av[2];
fake_av[0] = resolve_refdup("HEAD",
- RESOLVE_REF_READING,
- oid.hash, NULL);
+ RESOLVE_REF_READING, &oid,
+ NULL);
fake_av[1] = NULL;
av = fake_av;
ac = 1;
die(Q_("only %d entry can be shown at one time.",
"only %d entries can be shown at one time.",
MAX_REVS), MAX_REVS);
- if (!dwim_ref(*av, strlen(*av), oid.hash, &ref))
+ if (!dwim_ref(*av, strlen(*av), &oid, &ref))
die(_("no such ref %s"), *av);
/* Has the base been specified? */
/* Ah, that is a date spec... */
timestamp_t at;
at = approxidate(reflog_base);
- read_ref_at(ref, flags, at, -1, oid.hash, NULL,
+ read_ref_at(ref, flags, at, -1, &oid, NULL,
NULL, NULL, &base);
}
}
timestamp_t timestamp;
int tz;
- if (read_ref_at(ref, flags, 0, base+i, oid.hash, &logmsg,
+ if (read_ref_at(ref, flags, 0, base + i, &oid, &logmsg,
×tamp, &tz, NULL)) {
reflog = i;
break;
}
head = resolve_refdup("HEAD", RESOLVE_REF_READING,
- head_oid.hash, NULL);
+ &head_oid, NULL);
if (with_current_branch && head) {
int has_head = 0;
if (!deref_tags)
return;
- if (!peel_ref(refname, peeled.hash)) {
+ if (!peel_ref(refname, &peeled)) {
hex = find_unique_abbrev(peeled.hash, abbrev);
printf("%s %s^{}\n", hex, refname);
}
struct object_id oid;
if ((starts_with(*pattern, "refs/") || !strcmp(*pattern, "HEAD")) &&
- !read_ref(*pattern, oid.hash)) {
+ !read_ref(*pattern, &oid)) {
show_one(*pattern, &oid);
}
else if (!quiet)
#include "remote.h"
#include "refs.h"
#include "connect.h"
+#include "revision.h"
+#include "diffcore.h"
+#include "diff.h"
+
+#define OPT_QUIET (1 << 0)
+#define OPT_CACHED (1 << 1)
+#define OPT_RECURSIVE (1 << 2)
+
+typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
+ void *cb_data);
static char *get_default_remote(void)
{
return 0;
}
+/* the result should be freed by the caller. */
+static char *get_submodule_displaypath(const char *path, const char *prefix)
+{
+ const char *super_prefix = get_super_prefix();
+
+ if (prefix && super_prefix) {
+ BUG("cannot have prefix '%s' and superprefix '%s'",
+ prefix, super_prefix);
+ } else if (prefix) {
+ struct strbuf sb = STRBUF_INIT;
+ char *displaypath = xstrdup(relative_path(path, prefix, &sb));
+ strbuf_release(&sb);
+ return displaypath;
+ } else if (super_prefix) {
+ return xstrfmt("%s%s", super_prefix, path);
+ } else {
+ return xstrdup(path);
+ }
+}
+
+static char *compute_rev_name(const char *sub_path, const char* object_id)
+{
+ struct strbuf sb = STRBUF_INIT;
+ const char ***d;
+
+ static const char *describe_bare[] = { NULL };
+
+ static const char *describe_tags[] = { "--tags", NULL };
+
+ static const char *describe_contains[] = { "--contains", NULL };
+
+ static const char *describe_all_always[] = { "--all", "--always", NULL };
+
+ static const char **describe_argv[] = { describe_bare, describe_tags,
+ describe_contains,
+ describe_all_always, NULL };
+
+ for (d = describe_argv; *d; d++) {
+ struct child_process cp = CHILD_PROCESS_INIT;
+ prepare_submodule_repo_env(&cp.env_array);
+ cp.dir = sub_path;
+ cp.git_cmd = 1;
+ cp.no_stderr = 1;
+
+ argv_array_push(&cp.args, "describe");
+ argv_array_pushv(&cp.args, *d);
+ argv_array_push(&cp.args, object_id);
+
+ if (!capture_command(&cp, &sb, 0)) {
+ strbuf_strip_suffix(&sb, "\n");
+ return strbuf_detach(&sb, NULL);
+ }
+ }
+
+ strbuf_release(&sb);
+ return NULL;
+}
+
struct module_list {
const struct cache_entry **entries;
int alloc, nr;
return 0;
}
-static void init_submodule(const char *path, const char *prefix, int quiet)
+static void for_each_listed_submodule(const struct module_list *list,
+ each_submodule_fn fn, void *cb_data)
+{
+ int i;
+ for (i = 0; i < list->nr; i++)
+ fn(list->entries[i], cb_data);
+}
+
+struct init_cb {
+ const char *prefix;
+ unsigned int flags;
+};
+
+#define INIT_CB_INIT { NULL, 0 }
+
+static void init_submodule(const char *path, const char *prefix,
+ unsigned int flags)
{
const struct submodule *sub;
struct strbuf sb = STRBUF_INIT;
char *upd = NULL, *url = NULL, *displaypath;
- if (prefix && get_super_prefix())
- die("BUG: cannot have prefix and superprefix");
- else if (prefix)
- displaypath = xstrdup(relative_path(path, prefix, &sb));
- else if (get_super_prefix()) {
- strbuf_addf(&sb, "%s%s", get_super_prefix(), path);
- displaypath = strbuf_detach(&sb, NULL);
- } else
- displaypath = xstrdup(path);
+ displaypath = get_submodule_displaypath(path, prefix);
sub = submodule_from_path(&null_oid, path);
* Set active flag for the submodule being initialized
*/
if (!is_submodule_active(the_repository, path)) {
- strbuf_reset(&sb);
strbuf_addf(&sb, "submodule.%s.active", sub->name);
git_config_set_gently(sb.buf, "true");
+ strbuf_reset(&sb);
}
/*
* To look up the url in .git/config, we must not fall back to
* .gitmodules, so look it up directly.
*/
- strbuf_reset(&sb);
strbuf_addf(&sb, "submodule.%s.url", sub->name);
if (git_config_get_string(sb.buf, &url)) {
if (!sub->url)
if (git_config_set_gently(sb.buf, url))
die(_("Failed to register url for submodule path '%s'"),
displaypath);
- if (!quiet)
+ if (!(flags & OPT_QUIET))
fprintf(stderr,
_("Submodule '%s' (%s) registered for path '%s'\n"),
sub->name, url, displaypath);
}
+ strbuf_reset(&sb);
/* Copy "update" setting when it is not set yet */
- strbuf_reset(&sb);
strbuf_addf(&sb, "submodule.%s.update", sub->name);
if (git_config_get_string(sb.buf, &upd) &&
sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
free(upd);
}
+static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)
+{
+ struct init_cb *info = cb_data;
+ init_submodule(list_item->name, info->prefix, info->flags);
+}
+
static int module_init(int argc, const char **argv, const char *prefix)
{
+ struct init_cb info = INIT_CB_INIT;
struct pathspec pathspec;
struct module_list list = MODULE_LIST_INIT;
int quiet = 0;
- int i;
struct option module_init_options[] = {
OPT__QUIET(&quiet, N_("Suppress output for initializing a submodule")),
if (!argc && git_config_get_value_multi("submodule.active"))
module_list_active(&list);
- for (i = 0; i < list.nr; i++)
- init_submodule(list.entries[i]->name, prefix, quiet);
+ info.prefix = prefix;
+ if (quiet)
+ info.flags |= OPT_QUIET;
+
+ for_each_listed_submodule(&list, init_submodule_cb, &info);
+
+ return 0;
+}
+
+struct status_cb {
+ const char *prefix;
+ unsigned int flags;
+};
+
+#define STATUS_CB_INIT { NULL, 0 }
+
+static void print_status(unsigned int flags, char state, const char *path,
+ const struct object_id *oid, const char *displaypath)
+{
+ if (flags & OPT_QUIET)
+ return;
+
+ printf("%c%s %s", state, oid_to_hex(oid), displaypath);
+
+ if (state == ' ' || state == '+')
+ printf(" (%s)", compute_rev_name(path, oid_to_hex(oid)));
+
+ printf("\n");
+}
+
+static int handle_submodule_head_ref(const char *refname,
+ const struct object_id *oid, int flags,
+ void *cb_data)
+{
+ struct object_id *output = cb_data;
+ if (oid)
+ oidcpy(output, oid);
+
+ return 0;
+}
+
+static void status_submodule(const char *path, const struct object_id *ce_oid,
+ unsigned int ce_flags, const char *prefix,
+ unsigned int flags)
+{
+ char *displaypath;
+ struct argv_array diff_files_args = ARGV_ARRAY_INIT;
+ struct rev_info rev;
+ int diff_files_result;
+
+ if (!submodule_from_path(&null_oid, path))
+ die(_("no submodule mapping found in .gitmodules for path '%s'"),
+ path);
+
+ displaypath = get_submodule_displaypath(path, prefix);
+
+ if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
+ print_status(flags, 'U', path, &null_oid, displaypath);
+ goto cleanup;
+ }
+
+ if (!is_submodule_active(the_repository, path)) {
+ print_status(flags, '-', path, ce_oid, displaypath);
+ goto cleanup;
+ }
+
+ argv_array_pushl(&diff_files_args, "diff-files",
+ "--ignore-submodules=dirty", "--quiet", "--",
+ path, NULL);
+
+ git_config(git_diff_basic_config, NULL);
+ init_revisions(&rev, prefix);
+ rev.abbrev = 0;
+ diff_files_args.argc = setup_revisions(diff_files_args.argc,
+ diff_files_args.argv,
+ &rev, NULL);
+ diff_files_result = run_diff_files(&rev, 0);
+
+ if (!diff_result_code(&rev.diffopt, diff_files_result)) {
+ print_status(flags, ' ', path, ce_oid,
+ displaypath);
+ } else if (!(flags & OPT_CACHED)) {
+ struct object_id oid;
+
+ if (refs_head_ref(get_submodule_ref_store(path),
+ handle_submodule_head_ref, &oid))
+ die(_("could not resolve HEAD ref inside the"
+ "submodule '%s'"), path);
+
+ print_status(flags, '+', path, &oid, displaypath);
+ } else {
+ print_status(flags, '+', path, ce_oid, displaypath);
+ }
+
+ if (flags & OPT_RECURSIVE) {
+ struct child_process cpr = CHILD_PROCESS_INIT;
+
+ cpr.git_cmd = 1;
+ cpr.dir = path;
+ prepare_submodule_repo_env(&cpr.env_array);
+
+ argv_array_push(&cpr.args, "--super-prefix");
+ argv_array_pushf(&cpr.args, "%s/", displaypath);
+ argv_array_pushl(&cpr.args, "submodule--helper", "status",
+ "--recursive", NULL);
+
+ if (flags & OPT_CACHED)
+ argv_array_push(&cpr.args, "--cached");
+
+ if (flags & OPT_QUIET)
+ argv_array_push(&cpr.args, "--quiet");
+
+ if (run_command(&cpr))
+ die(_("failed to recurse into submodule '%s'"), path);
+ }
+
+cleanup:
+ argv_array_clear(&diff_files_args);
+ free(displaypath);
+}
+
+static void status_submodule_cb(const struct cache_entry *list_item,
+ void *cb_data)
+{
+ struct status_cb *info = cb_data;
+ status_submodule(list_item->name, &list_item->oid, list_item->ce_flags,
+ info->prefix, info->flags);
+}
+
+static int module_status(int argc, const char **argv, const char *prefix)
+{
+ struct status_cb info = STATUS_CB_INIT;
+ struct pathspec pathspec;
+ struct module_list list = MODULE_LIST_INIT;
+ int quiet = 0;
+
+ struct option module_status_options[] = {
+ OPT__QUIET(&quiet, N_("Suppress submodule status output")),
+ OPT_BIT(0, "cached", &info.flags, N_("Use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
+ OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
+ OPT_END()
+ };
+
+ const char *const git_submodule_helper_usage[] = {
+ N_("git submodule status [--quiet] [--cached] [--recursive] [<path>...]"),
+ NULL
+ };
+
+ argc = parse_options(argc, argv, prefix, module_status_options,
+ git_submodule_helper_usage, 0);
+
+ if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
+ return 1;
+
+ info.prefix = prefix;
+ if (quiet)
+ info.flags |= OPT_QUIET;
+
+ for_each_listed_submodule(&list, status_submodule_cb, &info);
return 0;
}
argv++;
argc--;
/* Get the submodule's head ref and determine if it is detached */
- head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
+ head = resolve_refdup("HEAD", 0, &head_oid, NULL);
if (!head)
die(_("Failed to resolve HEAD as a valid ref."));
if (!strcmp(head, "HEAD"))
{"resolve-relative-url", resolve_relative_url, 0},
{"resolve-relative-url-test", resolve_relative_url_test, 0},
{"init", module_init, SUPPORT_SUPER_PREFIX},
+ {"status", module_status, SUPPORT_SUPER_PREFIX},
{"remote-branch", resolve_remote_submodule_branch, 0},
{"push-check", push_check, 0},
{"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
die("Cannot delete %s, not a symbolic ref", argv[0]);
if (!strcmp(argv[0], "HEAD"))
die("deleting '%s' is not allowed", argv[0]);
- return delete_ref(NULL, argv[0], NULL, REF_NODEREF);
+ return delete_ref(NULL, argv[0], NULL, REF_NO_DEREF);
}
switch (argc) {
for (p = argv; *p; p++) {
strbuf_reset(&ref);
strbuf_addf(&ref, "refs/tags/%s", *p);
- if (read_ref(ref.buf, oid.hash)) {
+ if (read_ref(ref.buf, &oid)) {
error(_("tag '%s' not found."), *p);
had_error = 1;
continue;
static int delete_tag(const char *name, const char *ref,
const struct object_id *oid, const void *cb_data)
{
- if (delete_ref(NULL, ref, oid->hash, 0))
+ if (delete_ref(NULL, ref, oid, 0))
return 1;
printf(_("Deleted tag '%s' (was %s)\n"), name, find_unique_abbrev(oid->hash, DEFAULT_ABBREV));
return 0;
if (strbuf_check_tag_ref(&ref, tag))
die(_("'%s' is not a valid tag name."), tag);
- if (read_ref(ref.buf, prev.hash))
+ if (read_ref(ref.buf, &prev))
oidclr(&prev);
else if (!force)
die(_("tag '%s' already exists"), tag);
transaction = ref_transaction_begin(&err);
if (!transaction ||
- ref_transaction_update(transaction, ref.buf, object.hash, prev.hash,
+ ref_transaction_update(transaction, ref.buf, &object, &prev,
create_reflog ? REF_FORCE_CREATE_REFLOG : 0,
reflog_msg.buf, &err) ||
ref_transaction_commit(transaction, &err))
if (S_ISGITLINK(ce->ce_mode)) {
/* Do nothing to the index if there is no HEAD! */
- if (resolve_gitlink_ref(path, "HEAD", oid.hash) < 0)
+ if (resolve_gitlink_ref(path, "HEAD", &oid) < 0)
return 0;
return add_one_path(ce, path, len, st);
}
/* No match - should we add it as a gitlink? */
- if (!resolve_gitlink_ref(path, "HEAD", oid.hash))
+ if (!resolve_gitlink_ref(path, "HEAD", &oid))
return add_one_path(NULL, path, len, st);
/* Error out. */
static void read_head_pointers(void)
{
- if (read_ref("HEAD", head_oid.hash))
+ if (read_ref("HEAD", &head_oid))
die("No HEAD -- no initial commit yet?");
- if (read_ref("MERGE_HEAD", merge_head_oid.hash)) {
+ if (read_ref("MERGE_HEAD", &merge_head_oid)) {
fprintf(stderr, "Not in the middle of a merge.\n");
exit(0);
}
PATHSPEC_PREFER_CWD,
prefix, av + 1);
- if (read_ref("HEAD", head_oid.hash))
+ if (read_ref("HEAD", &head_oid))
/* If there is no HEAD, that means it is an initial
* commit. Update everything in the index.
*/
die("update %s: extra input: %s", refname, next);
if (ref_transaction_update(transaction, refname,
- new_oid.hash, have_old ? old_oid.hash : NULL,
+ &new_oid, have_old ? &old_oid : NULL,
update_flags | create_reflog_flag,
msg, &err))
die("%s", err.buf);
if (*next != line_termination)
die("create %s: extra input: %s", refname, next);
- if (ref_transaction_create(transaction, refname, new_oid.hash,
+ if (ref_transaction_create(transaction, refname, &new_oid,
update_flags | create_reflog_flag,
msg, &err))
die("%s", err.buf);
die("delete %s: extra input: %s", refname, next);
if (ref_transaction_delete(transaction, refname,
- have_old ? old_oid.hash : NULL,
+ have_old ? &old_oid : NULL,
update_flags, msg, &err))
die("%s", err.buf);
if (*next != line_termination)
die("verify %s: extra input: %s", refname, next);
- if (ref_transaction_verify(transaction, refname, old_oid.hash,
+ if (ref_transaction_verify(transaction, refname, &old_oid,
update_flags, &err))
die("%s", err.buf);
static const char *parse_cmd_option(struct strbuf *input, const char *next)
{
if (!strncmp(next, "no-deref", 8) && next[8] == line_termination)
- update_flags |= REF_NODEREF;
+ update_flags |= REF_NO_DEREF;
else
die("option unknown: %s", next);
return next + 8;
}
if (no_deref)
- flags = REF_NODEREF;
+ flags = REF_NO_DEREF;
if (delete)
/*
* For purposes of backwards compatibility, we treat
* NULL_SHA1 as "don't care" here:
*/
return delete_ref(msg, refname,
- (oldval && !is_null_oid(&oldoid)) ? oldoid.hash : NULL,
+ (oldval && !is_null_oid(&oldoid)) ? &oldoid : NULL,
flags);
else
- return update_ref(msg, refname, oid.hash, oldval ? oldoid.hash : NULL,
+ return update_ref(msg, refname, &oid, oldval ? &oldoid : NULL,
flags | create_reflog_flag,
UPDATE_REFS_DIE_ON_ERR);
}
if (wt->is_bare)
printf("bare\n");
else {
- printf("HEAD %s\n", sha1_to_hex(wt->head_sha1));
+ printf("HEAD %s\n", oid_to_hex(&wt->head_oid));
if (wt->is_detached)
printf("detached\n");
else if (wt->head_ref)
strbuf_addstr(&sb, "(bare)");
else {
strbuf_addf(&sb, "%-*s ", abbrev_len,
- find_unique_abbrev(wt->head_sha1, DEFAULT_ABBREV));
+ find_unique_abbrev(wt->head_oid.hash, DEFAULT_ABBREV));
if (wt->is_detached)
strbuf_addstr(&sb, "(detached HEAD)");
else if (wt->head_ref) {
if (path_len > *maxlen)
*maxlen = path_len;
- sha1_len = strlen(find_unique_abbrev(wt[i]->head_sha1, *abbrev));
+ sha1_len = strlen(find_unique_abbrev(wt[i]->head_oid.hash, *abbrev));
if (sha1_len > *abbrev)
*abbrev = sha1_len;
}
if (e->item->flags & UNINTERESTING)
continue;
- if (dwim_ref(e->name, strlen(e->name), oid.hash, &ref) != 1)
+ if (dwim_ref(e->name, strlen(e->name), &oid, &ref) != 1)
goto skip_write_ref;
- if (read_ref_full(e->name, RESOLVE_REF_READING, oid.hash, &flag))
+ if (read_ref_full(e->name, RESOLVE_REF_READING, &oid, &flag))
flag = 0;
display_ref = (flag & REF_ISSYMREF) ? e->name : ref;
int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, const char *index_path, int flags, const char *prefix)
{
- int entries, was_valid, newfd;
+ int entries, was_valid;
struct lock_file lock_file = LOCK_INIT;
int ret = 0;
- newfd = hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR);
+ hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR);
entries = read_index_from(index_state, index_path);
if (entries < 0) {
ret = WRITE_TREE_UNMERGED_INDEX;
goto out;
}
- if (0 <= newfd) {
- if (!write_locked_index(index_state, &lock_file, COMMIT_LOCK))
- newfd = -1;
- }
+ write_locked_index(index_state, &lock_file, COMMIT_LOCK);
/* Not being able to write is fine -- we are only interested
* in updating the cache-tree part, and if the next caller
* ends up using the old index with unupdated cache-tree part
hashcpy(sha1, index_state->cache_tree->oid.hash);
out:
- if (0 <= newfd)
- rollback_lock_file(&lock_file);
+ rollback_lock_file(&lock_file);
return ret;
}
extern int read_index_from(struct index_state *, const char *path);
extern int is_index_unborn(struct index_state *);
extern int read_index_unmerged(struct index_state *);
+
+/* For use with `write_locked_index()`. */
#define COMMIT_LOCK (1 << 0)
-#define CLOSE_LOCK (1 << 1)
+
+/*
+ * Write the index while holding an already-taken lock. Close the lock,
+ * and if `COMMIT_LOCK` is given, commit it.
+ *
+ * Unless a split index is in use, write the index into the lockfile.
+ *
+ * With a split index, write the shared index to a temporary file,
+ * adjust its permissions and rename it into place, then write the
+ * split index to the lockfile. If the temporary file for the shared
+ * index cannot be created, fall back to the behavior described in
+ * the previous paragraph.
+ *
+ * With `COMMIT_LOCK`, the lock is always committed or rolled back.
+ * Without it, the lock is closed, but neither committed nor rolled
+ * back.
+ */
extern int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags);
+
extern int discard_index(struct index_state *);
extern void move_index_extensions(struct index_state *dst, struct index_state *src);
extern int unmerged_index(const struct index_state *);
extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
extern struct cache_entry *refresh_cache_entry(struct cache_entry *, unsigned int);
+/*
+ * Opportunistically update the index but do not complain if we can't.
+ * The lockfile is always committed or rolled back.
+ */
extern void update_index_if_able(struct index_state *, struct lock_file *);
extern int hold_locked_index(struct lock_file *, int);
extern int get_sha1_hex(const char *hex, unsigned char *sha1);
extern int get_oid_hex(const char *hex, struct object_id *sha1);
+/*
+ * Read `len` pairs of hexadecimal digits from `hex` and write the
+ * values to `binary` as `len` bytes. Return 0 on success, or -1 if
+ * the input does not consist of hex digits).
+ */
+extern int hex_to_bytes(unsigned char *binary, const char *hex, size_t len);
+
/*
* Convert a binary sha1 to its hex equivalent. The `_r` variant is reentrant,
* and writes the NUL-terminated output to the buffer `out`, which must be at
linux)
export GIT_TEST_HTTPD=YesPlease
- mkdir --parents custom/p4
- pushd custom/p4
+ mkdir --parents "$P4_PATH"
+ pushd "$P4_PATH"
wget --quiet "$P4WHENCE/bin.linux26x86_64/p4d"
wget --quiet "$P4WHENCE/bin.linux26x86_64/p4"
chmod u+x p4d
chmod u+x p4
- export PATH="$(pwd):$PATH"
popd
- mkdir --parents custom/git-lfs
- pushd custom/git-lfs
+ mkdir --parents "$GIT_LFS_PATH"
+ pushd "$GIT_LFS_PATH"
wget --quiet "$LFSWHENCE/git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz"
tar --extract --gunzip --file "git-lfs-linux-amd64-$LINUX_GIT_LFS_VERSION.tar.gz"
cp git-lfs-$LINUX_GIT_LFS_VERSION/git-lfs .
- export PATH="$(pwd):$PATH"
popd
;;
osx)
set -e
skip_branch_tip_with_tag
+
+case "${TRAVIS_OS_NAME:-linux}" in
+linux)
+ P4_PATH="$(pwd)/custom/p4"
+ GIT_LFS_PATH="$(pwd)/custom/git-lfs"
+ export PATH="$GIT_LFS_PATH:$P4_PATH:$PATH"
+ ;;
+esac
if (stdout_is_tty < 0)
stdout_is_tty = isatty(1);
*colopts &= ~COL_ENABLE_MASK;
- if (stdout_is_tty)
+ if (stdout_is_tty || pager_in_use())
*colopts |= COL_ENABLED;
}
return 0;
int show_file_header)
{
struct diff_options *opt = &rev->diffopt;
- int abbrev = DIFF_OPT_TST(opt, FULL_INDEX) ? GIT_SHA1_HEXSZ : DEFAULT_ABBREV;
+ int abbrev = opt->flags.full_index ? GIT_SHA1_HEXSZ : DEFAULT_ABBREV;
const char *a_prefix = opt->a_prefix ? opt->a_prefix : "a/";
const char *b_prefix = opt->b_prefix ? opt->b_prefix : "b/";
const char *c_meta = diff_get_color_opt(opt, DIFF_METAINFO);
userdiff = userdiff_find_by_path(elem->path);
if (!userdiff)
userdiff = userdiff_find_by_name("default");
- if (DIFF_OPT_TST(opt, ALLOW_TEXTCONV))
+ if (opt->flags.allow_textconv)
textconv = userdiff_get_textconv(userdiff);
/* Read the result of merge first */
elem->mode = canon_mode(st.st_mode);
} else if (S_ISDIR(st.st_mode)) {
struct object_id oid;
- if (resolve_gitlink_ref(elem->path, "HEAD", oid.hash) < 0)
+ if (resolve_gitlink_ref(elem->path, "HEAD", &oid) < 0)
result = grab_blob(&elem->oid, elem->mode,
&result_size, NULL, NULL);
else
diffopts = *opt;
copy_pathspec(&diffopts.pathspec, &opt->pathspec);
- DIFF_OPT_SET(&diffopts, RECURSIVE);
- DIFF_OPT_CLR(&diffopts, ALLOW_EXTERNAL);
+ diffopts.flags.recursive = 1;
+ diffopts.flags.allow_external = 0;
/* find set of paths that everybody touches
*
* NOTE please keep this semantically in sync with diffcore_std()
*/
need_generic_pathscan = opt->skip_stat_unmatch ||
- DIFF_OPT_TST(opt, FOLLOW_RENAMES) ||
+ opt->flags.follow_renames ||
opt->break_opt != -1 ||
opt->detect_rename ||
opt->pickaxe ||
return memcpy(malloc_startup(len), buffer, len);
}
+static void maybe_redirect_std_handle(const wchar_t *key, DWORD std_id, int fd,
+ DWORD desired_access, DWORD flags)
+{
+ DWORD create_flag = fd ? OPEN_ALWAYS : OPEN_EXISTING;
+ wchar_t buf[MAX_PATH];
+ DWORD max = ARRAY_SIZE(buf);
+ HANDLE handle;
+ DWORD ret = GetEnvironmentVariableW(key, buf, max);
+
+ if (!ret || ret >= max)
+ return;
+
+ /* make sure this does not leak into child processes */
+ SetEnvironmentVariableW(key, NULL);
+ if (!wcscmp(buf, L"off")) {
+ close(fd);
+ handle = GetStdHandle(std_id);
+ if (handle != INVALID_HANDLE_VALUE)
+ CloseHandle(handle);
+ return;
+ }
+ if (std_id == STD_ERROR_HANDLE && !wcscmp(buf, L"2>&1")) {
+ handle = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (handle == INVALID_HANDLE_VALUE) {
+ close(fd);
+ handle = GetStdHandle(std_id);
+ if (handle != INVALID_HANDLE_VALUE)
+ CloseHandle(handle);
+ } else {
+ int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY);
+ SetStdHandle(std_id, handle);
+ dup2(new_fd, fd);
+ /* do *not* close the new_fd: that would close stdout */
+ }
+ return;
+ }
+ handle = CreateFileW(buf, desired_access, 0, NULL, create_flag,
+ flags, NULL);
+ if (handle != INVALID_HANDLE_VALUE) {
+ int new_fd = _open_osfhandle((intptr_t)handle, O_BINARY);
+ SetStdHandle(std_id, handle);
+ dup2(new_fd, fd);
+ close(new_fd);
+ }
+}
+
+static void maybe_redirect_std_handles(void)
+{
+ maybe_redirect_std_handle(L"GIT_REDIRECT_STDIN", STD_INPUT_HANDLE, 0,
+ GENERIC_READ, FILE_ATTRIBUTE_NORMAL);
+ maybe_redirect_std_handle(L"GIT_REDIRECT_STDOUT", STD_OUTPUT_HANDLE, 1,
+ GENERIC_WRITE, FILE_ATTRIBUTE_NORMAL);
+ maybe_redirect_std_handle(L"GIT_REDIRECT_STDERR", STD_ERROR_HANDLE, 2,
+ GENERIC_WRITE, FILE_FLAG_NO_BUFFERING);
+}
+
void mingw_startup(void)
{
int i, maxlen, argc;
wchar_t **wenv, **wargv;
_startupinfo si;
+ maybe_redirect_std_handles();
+
/* get wide char arguments and environment */
si.newmode = 0;
if (__wgetmainargs(&argc, &wargv, &wenv, _CRT_glob, &si) < 0)
{
int ret = 0, remove = 0;
char *filename_buf = NULL;
- struct lock_file *lock;
+ struct lock_file lock = LOCK_INIT;
int out_fd;
char buf[1024];
FILE *config_file = NULL;
if (!config_filename)
config_filename = filename_buf = git_pathdup("config");
- lock = xcalloc(1, sizeof(struct lock_file));
- out_fd = hold_lock_file_for_update(lock, config_filename, 0);
+ out_fd = hold_lock_file_for_update(&lock, config_filename, 0);
if (out_fd < 0) {
ret = error("could not lock config file %s", config_filename);
goto out;
goto out;
}
- if (chmod(get_lock_file_path(lock), st.st_mode & 07777) < 0) {
+ if (chmod(get_lock_file_path(&lock), st.st_mode & 07777) < 0) {
ret = error_errno("chmod on %s failed",
- get_lock_file_path(lock));
+ get_lock_file_path(&lock));
goto out;
}
*/
if (copystr.len > 0) {
if (write_in_full(out_fd, copystr.buf, copystr.len) != copystr.len) {
- ret = write_error(get_lock_file_path(lock));
+ ret = write_error(get_lock_file_path(&lock));
goto out;
}
strbuf_reset(©str);
store.baselen = strlen(new_name);
if (!copy) {
if (write_section(out_fd, new_name) < 0) {
- ret = write_error(get_lock_file_path(lock));
+ ret = write_error(get_lock_file_path(&lock));
goto out;
}
/*
}
if (write_in_full(out_fd, output, length) < 0) {
- ret = write_error(get_lock_file_path(lock));
+ ret = write_error(get_lock_file_path(&lock));
goto out;
}
}
*/
if (copystr.len > 0) {
if (write_in_full(out_fd, copystr.buf, copystr.len) != copystr.len) {
- ret = write_error(get_lock_file_path(lock));
+ ret = write_error(get_lock_file_path(&lock));
goto out;
}
strbuf_reset(©str);
fclose(config_file);
config_file = NULL;
commit_and_out:
- if (commit_lock_file(lock) < 0)
+ if (commit_lock_file(&lock) < 0)
ret = error_errno("could not write config file %s",
config_filename);
out:
if (config_file)
fclose(config_file);
- rollback_lock_file(lock);
+ rollback_lock_file(&lock);
out_no_rollback:
free(filename_buf);
return ret;
*
* Returns 0 if everything is connected, non-zero otherwise.
*/
-int check_connected(sha1_iterate_fn fn, void *cb_data,
+int check_connected(oid_iterate_fn fn, void *cb_data,
struct check_connected_options *opt)
{
struct child_process rev_list = CHILD_PROCESS_INIT;
struct check_connected_options defaults = CHECK_CONNECTED_INIT;
- char commit[41];
- unsigned char sha1[20];
+ char commit[GIT_MAX_HEXSZ + 1];
+ struct object_id oid;
int err = 0;
struct packed_git *new_pack = NULL;
struct transport *transport;
opt = &defaults;
transport = opt->transport;
- if (fn(cb_data, sha1)) {
+ if (fn(cb_data, &oid)) {
if (opt->err_fd)
close(opt->err_fd);
return err;
sigchain_push(SIGPIPE, SIG_IGN);
- commit[40] = '\n';
+ commit[GIT_SHA1_HEXSZ] = '\n';
do {
/*
* If index-pack already checked that:
* are sure the ref is good and not sending it to
* rev-list for verification.
*/
- if (new_pack && find_pack_entry_one(sha1, new_pack))
+ if (new_pack && find_pack_entry_one(oid.hash, new_pack))
continue;
- memcpy(commit, sha1_to_hex(sha1), 40);
- if (write_in_full(rev_list.in, commit, 41) < 0) {
+ memcpy(commit, oid_to_hex(&oid), GIT_SHA1_HEXSZ);
+ if (write_in_full(rev_list.in, commit, GIT_SHA1_HEXSZ + 1) < 0) {
if (errno != EPIPE && errno != EINVAL)
error_errno(_("failed write to rev-list"));
err = -1;
break;
}
- } while (!fn(cb_data, sha1));
+ } while (!fn(cb_data, &oid));
if (close(rev_list.in))
err = error_errno(_("failed to close rev-list's stdin"));
* When called after returning the name for the last object, return -1
* to signal EOF, otherwise return 0.
*/
-typedef int (*sha1_iterate_fn)(void *, unsigned char [20]);
+typedef int (*oid_iterate_fn)(void *, struct object_id *oid);
/*
* Named-arguments struct for check_connected. All arguments are
*
* If "opt" is NULL, behaves as if CHECK_CONNECTED_INIT was passed.
*/
-int check_connected(sha1_iterate_fn fn, void *cb_data,
+int check_connected(oid_iterate_fn fn, void *cb_data,
struct check_connected_options *opt);
#endif /* CONNECTED_H */
--*)
__gitcomp "
--quiet --ours --theirs --track --no-track --merge
- --conflict= --orphan --patch
+ --conflict= --orphan --patch --detach --ignore-skip-worktree-bits
+ --recurse-submodules --no-recurse-submodules
"
;;
*)
advice.rmHints
advice.statusHints
advice.statusUoption
+ advice.ignoredHook
alias.
am.keepcr
am.threeWay
items = secret_service_search_sync(service,
SECRET_SCHEMA_COMPAT_NETWORK,
attributes,
- SECRET_SEARCH_LOAD_SECRETS,
+ SECRET_SEARCH_LOAD_SECRETS | SECRET_SEARCH_UNLOCK,
NULL,
&error);
g_hash_table_unref(attributes);
static void write_item(const char *what, LPCWSTR wbuf, int wlen)
{
char *buf;
+
+ if (!wbuf || !wlen) {
+ printf("%s=\n", what);
+ return;
+ }
+
int len = WideCharToMultiByte(CP_UTF8, 0, wbuf, wlen, NULL, 0, NULL,
FALSE);
buf = xmalloc(len);
static int match_cred(const CREDENTIALW *cred)
{
LPCWSTR target = cred->TargetName;
- if (wusername && wcscmp(wusername, cred->UserName))
+ if (wusername && wcscmp(wusername, cred->UserName ? cred->UserName : L""))
return 0;
return match_part(&target, L"git", L":") &&
for (i = 0; i < num_creds; ++i)
if (match_cred(creds[i])) {
write_item("username", creds[i]->UserName,
- wcslen(creds[i]->UserName));
+ creds[i]->UserName ? wcslen(creds[i]->UserName) : 0);
write_item("password",
(LPCWSTR)creds[i]->CredentialBlob,
creds[i]->CredentialBlobSize / sizeof(WCHAR));
use 5.008;
use strict;
+use POSIX;
use Git;
BEGIN {
$filename =~ s/ /_/g;
# Decode forbidden characters encoded in clean_filename
$filename =~ s/_%_([0-9a-fA-F][0-9a-fA-F])/sprintf('%c', hex($1))/ge;
- return $filename;
+ return substr($filename, 0, NAME_MAX-length('.mw'));
}
sub connect_maybe {
if (has_symlink_leading_path(ce->name, ce_namelen(ce)))
return 1;
if (S_ISDIR(st->st_mode)) {
- unsigned char sub[20];
+ struct object_id sub;
/*
* If ce is already a gitlink, we can have a plain
* a directory --- the blob was removed!
*/
if (!S_ISGITLINK(ce->ce_mode) &&
- resolve_gitlink_ref(ce->name, "HEAD", sub))
+ resolve_gitlink_ref(ce->name, "HEAD", &sub))
return 1;
}
return 0;
{
int changed = ce_match_stat(ce, st, ce_option);
if (S_ISGITLINK(ce->ce_mode)) {
- unsigned orig_flags = diffopt->flags;
- if (!DIFF_OPT_TST(diffopt, OVERRIDE_SUBMODULE_CONFIG))
+ struct diff_flags orig_flags = diffopt->flags;
+ if (!diffopt->flags.override_submodule_config)
set_diffopt_flags_from_submodule_config(diffopt, ce->name);
- if (DIFF_OPT_TST(diffopt, IGNORE_SUBMODULES))
+ if (diffopt->flags.ignore_submodules)
changed = 0;
- else if (!DIFF_OPT_TST(diffopt, IGNORE_DIRTY_SUBMODULES)
- && (!changed || DIFF_OPT_TST(diffopt, DIRTY_SUBMODULES)))
- *dirty_submodule = is_submodule_modified(ce->name, DIFF_OPT_TST(diffopt, IGNORE_UNTRACKED_IN_SUBMODULES));
+ else if (!diffopt->flags.ignore_dirty_submodules &&
+ (!changed || diffopt->flags.dirty_submodules))
+ *dirty_submodule = is_submodule_modified(ce->name,
+ diffopt->flags.ignore_untracked_in_submodules);
diffopt->flags = orig_flags;
}
return changed;
if (!changed && !dirty_submodule) {
ce_mark_uptodate(ce);
- if (!DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
+ if (!revs->diffopt.flags.find_copies_harder)
continue;
}
oldmode = ce->ce_mode;
oldmode = old->ce_mode;
if (mode == oldmode && !oidcmp(oid, &old->oid) && !dirty_submodule &&
- !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER))
+ !revs->diffopt.flags.find_copies_harder)
return 0;
diff_change(&revs->diffopt, oldmode, mode,
opts.head_idx = 1;
opts.index_only = cached;
opts.diff_index_cached = (cached &&
- !DIFF_OPT_TST(&revs->diffopt, FIND_COPIES_HARDER));
+ !revs->diffopt.flags.find_copies_harder);
opts.merge = 1;
opts.fn = oneway_diff;
opts.unpack_data = revs;
return 0;
}
-int index_differs_from(const char *def, int diff_flags,
+int index_differs_from(const char *def, const struct diff_flags *flags,
int ita_invisible_in_index)
{
struct rev_info rev;
memset(&opt, 0, sizeof(opt));
opt.def = def;
setup_revisions(0, NULL, &rev, &opt);
- DIFF_OPT_SET(&rev.diffopt, QUICK);
- DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
- rev.diffopt.flags |= diff_flags;
+ rev.diffopt.flags.quick = 1;
+ rev.diffopt.flags.exit_with_status = 1;
+ if (flags)
+ diff_flags_or(&rev.diffopt.flags, flags);
rev.diffopt.ita_invisible_in_index = ita_invisible_in_index;
run_diff_index(&rev, 1);
object_array_clear(&rev.pending);
- return (DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0);
+ return (rev.diffopt.flags.has_changes != 0);
}
} else {
struct diff_filespec *d1, *d2;
- if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
+ if (o->flags.reverse_diff) {
SWAP(mode1, mode2);
SWAP(name1, name2);
}
if (!revs->diffopt.output_format)
revs->diffopt.output_format = DIFF_FORMAT_PATCH;
- DIFF_OPT_SET(&revs->diffopt, NO_INDEX);
+ revs->diffopt.flags.no_index = 1;
- DIFF_OPT_SET(&revs->diffopt, RELATIVE_NAME);
+ revs->diffopt.flags.relative_name = 1;
revs->diffopt.prefix = prefix;
revs->max_count = -2;
diff_setup_done(&revs->diffopt);
setup_diff_pager(&revs->diffopt);
- DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
+ revs->diffopt.flags.exit_with_status = 1;
if (queue_diff(&revs->diffopt, paths[0], paths[1]))
exit(1);
for (i = 0; i < params.nr; i++) {
const char *p = params.items[i].string;
if (!strcmp(p, "changes")) {
- DIFF_OPT_CLR(options, DIRSTAT_BY_LINE);
- DIFF_OPT_CLR(options, DIRSTAT_BY_FILE);
+ options->flags.dirstat_by_line = 0;
+ options->flags.dirstat_by_file = 0;
} else if (!strcmp(p, "lines")) {
- DIFF_OPT_SET(options, DIRSTAT_BY_LINE);
- DIFF_OPT_CLR(options, DIRSTAT_BY_FILE);
+ options->flags.dirstat_by_line = 1;
+ options->flags.dirstat_by_file = 0;
} else if (!strcmp(p, "files")) {
- DIFF_OPT_CLR(options, DIRSTAT_BY_LINE);
- DIFF_OPT_SET(options, DIRSTAT_BY_FILE);
+ options->flags.dirstat_by_line = 0;
+ options->flags.dirstat_by_file = 1;
} else if (!strcmp(p, "noncumulative")) {
- DIFF_OPT_CLR(options, DIRSTAT_CUMULATIVE);
+ options->flags.dirstat_cumulative = 0;
} else if (!strcmp(p, "cumulative")) {
- DIFF_OPT_SET(options, DIRSTAT_CUMULATIVE);
+ options->flags.dirstat_cumulative = 1;
} else if (isdigit(*p)) {
char *end;
int permille = strtoul(p, &end, 10) * 10;
struct moved_entry *next_line;
};
-static int next_byte(const char **cp, const char **endp,
- const struct diff_options *diffopt)
-{
- int retval;
-
- if (*cp > *endp)
- return -1;
-
- if (isspace(**cp)) {
- if (DIFF_XDL_TST(diffopt, IGNORE_WHITESPACE_CHANGE)) {
- while (*cp < *endp && isspace(**cp))
- (*cp)++;
- /*
- * After skipping a couple of whitespaces,
- * we still have to account for one space.
- */
- return (int)' ';
- }
-
- if (DIFF_XDL_TST(diffopt, IGNORE_WHITESPACE)) {
- while (*cp < *endp && isspace(**cp))
- (*cp)++;
- /* return the first non-ws character via the usual below */
- }
- }
-
- retval = (unsigned char)(**cp);
- (*cp)++;
- return retval;
-}
-
static int moved_entry_cmp(const struct diff_options *diffopt,
const struct moved_entry *a,
const struct moved_entry *b,
const void *keydata)
{
- const char *ap = a->es->line, *ae = a->es->line + a->es->len;
- const char *bp = b->es->line, *be = b->es->line + b->es->len;
-
- if (!(diffopt->xdl_opts & XDF_WHITESPACE_FLAGS))
- return a->es->len != b->es->len || memcmp(ap, bp, a->es->len);
-
- if (DIFF_XDL_TST(diffopt, IGNORE_WHITESPACE_AT_EOL)) {
- while (ae > ap && isspace(*ae))
- ae--;
- while (be > bp && isspace(*be))
- be--;
- }
-
- while (1) {
- int ca, cb;
- ca = next_byte(&ap, &ae, diffopt);
- cb = next_byte(&bp, &be, diffopt);
- if (ca != cb)
- return 1;
- if (ca < 0)
- return 0;
- }
-}
-
-static unsigned get_string_hash(struct emitted_diff_symbol *es, struct diff_options *o)
-{
- if (o->xdl_opts & XDF_WHITESPACE_FLAGS) {
- static struct strbuf sb = STRBUF_INIT;
- const char *ap = es->line, *ae = es->line + es->len;
- int c;
-
- strbuf_reset(&sb);
- while (ae > ap && isspace(*ae))
- ae--;
- while ((c = next_byte(&ap, &ae, o)) > 0)
- strbuf_addch(&sb, c);
-
- return memhash(sb.buf, sb.len);
- } else {
- return memhash(es->line, es->len);
- }
+ return !xdiff_compare_lines(a->es->line, a->es->len,
+ b->es->line, b->es->len,
+ diffopt->xdl_opts);
}
static struct moved_entry *prepare_entry(struct diff_options *o,
struct moved_entry *ret = xmalloc(sizeof(*ret));
struct emitted_diff_symbol *l = &o->emitted_symbols->buf[line_no];
- ret->ent.hash = get_string_hash(l, o);
+ ret->ent.hash = xdiff_hash_string(l->line, l->len, o->xdl_opts);
ret->es = l;
ret->next_line = NULL;
struct emit_callback ecbdata;
struct strbuf out = STRBUF_INIT;
- if (diff_mnemonic_prefix && DIFF_OPT_TST(o, REVERSE_DIFF)) {
+ if (diff_mnemonic_prefix && o->flags.reverse_diff) {
a_prefix = o->b_prefix;
b_prefix = o->a_prefix;
} else {
dir.alloc = 0;
dir.nr = 0;
dir.permille = options->dirstat_permille;
- dir.cumulative = DIFF_OPT_TST(options, DIRSTAT_CUMULATIVE);
+ dir.cumulative = options->flags.dirstat_cumulative;
changed = 0;
for (i = 0; i < q->nr; i++) {
goto found_damage;
}
- if (DIFF_OPT_TST(options, DIRSTAT_BY_FILE)) {
+ if (options->flags.dirstat_by_file) {
/*
* In --dirstat-by-file mode, we don't really need to
* look at the actual file contents at all.
dir.alloc = 0;
dir.nr = 0;
dir.permille = options->dirstat_permille;
- dir.cumulative = DIFF_OPT_TST(options, DIRSTAT_CUMULATIVE);
+ dir.cumulative = options->flags.dirstat_cumulative;
changed = 0;
for (i = 0; i < data->nr; i++) {
const char *line_prefix = diff_line_prefix(o);
diff_set_mnemonic_prefix(o, "a/", "b/");
- if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
+ if (o->flags.reverse_diff) {
a_prefix = o->b_prefix;
b_prefix = o->a_prefix;
} else {
return;
}
- if (DIFF_OPT_TST(o, ALLOW_TEXTCONV)) {
+ if (o->flags.allow_textconv) {
textconv_one = get_textconv(one);
textconv_two = get_textconv(two);
}
header.len, 0);
strbuf_reset(&header);
goto free_ab_and_return;
- } else if (!DIFF_OPT_TST(o, TEXT) &&
+ } else if (!o->flags.text &&
( (!textconv_one && diff_filespec_is_binary(one)) ||
(!textconv_two && diff_filespec_is_binary(two)) )) {
struct strbuf sb = STRBUF_INIT;
if (!one->data && !two->data &&
S_ISREG(one->mode) && S_ISREG(two->mode) &&
- !DIFF_OPT_TST(o, BINARY)) {
+ !o->flags.binary) {
if (!oidcmp(&one->oid, &two->oid)) {
if (must_show_header)
emit_diff_symbol(o, DIFF_SYMBOL_HEADER,
}
emit_diff_symbol(o, DIFF_SYMBOL_HEADER, header.buf, header.len, 0);
strbuf_reset(&header);
- if (DIFF_OPT_TST(o, BINARY))
+ if (o->flags.binary)
emit_binary_diff(o, &mf1, &mf2);
else {
strbuf_addf(&sb, "%sBinary files %s and %s differ\n",
xecfg.ctxlen = o->context;
xecfg.interhunkctxlen = o->interhunkcontext;
xecfg.flags = XDL_EMIT_FUNCNAMES;
- if (DIFF_OPT_TST(o, FUNCCONTEXT))
+ if (o->flags.funccontext)
xecfg.flags |= XDL_EMIT_FUNCCONTEXT;
if (pe)
xdiff_set_find_func(&xecfg, pe->pattern, pe->cflags);
diff_free_filespec_data(one);
diff_free_filespec_data(two);
if (data.status)
- DIFF_OPT_SET(o, CHECK_FAILED);
+ o->flags.check_failed = 1;
}
struct diff_filespec *alloc_filespec(const char *path)
int fd;
if (lstat(s->path, &st) < 0) {
- if (errno == ENOENT) {
- err_empty:
- err = -1;
- empty:
- s->data = (char *)"";
- s->size = 0;
- return err;
- }
+ err_empty:
+ err = -1;
+ empty:
+ s->data = (char *)"";
+ s->size = 0;
+ return err;
}
s->size = xsize_t(st.st_size);
if (!s->size)
*must_show_header = 0;
}
if (one && two && oidcmp(&one->oid, &two->oid)) {
- int abbrev = DIFF_OPT_TST(o, FULL_INDEX) ? 40 : DEFAULT_ABBREV;
+ int abbrev = o->flags.full_index ? 40 : DEFAULT_ABBREV;
- if (DIFF_OPT_TST(o, BINARY)) {
+ if (o->flags.binary) {
mmfile_t mf;
if ((!fill_mmfile(&mf, one) && diff_filespec_is_binary(one)) ||
(!fill_mmfile(&mf, two) && diff_filespec_is_binary(two)))
int must_show_header = 0;
- if (DIFF_OPT_TST(o, ALLOW_EXTERNAL)) {
+ if (o->flags.allow_external) {
struct userdiff_driver *drv = userdiff_find_by_path(attr_path);
if (drv && drv->external)
pgm = drv->external;
if (o->prefix_length)
strip_prefix(o->prefix_length, &name, &other);
- if (!DIFF_OPT_TST(o, ALLOW_EXTERNAL))
+ if (!o->flags.allow_external)
pgm = NULL;
if (DIFF_PAIR_UNMERGED(p)) {
options->context = diff_context_default;
options->interhunkcontext = diff_interhunk_context_default;
options->ws_error_highlight = ws_error_highlight_default;
- DIFF_OPT_SET(options, RENAME_EMPTY);
+ options->flags.rename_empty = 1;
/* pathchange left =NULL by default */
options->change = diff_change;
if (DIFF_XDL_TST(options, IGNORE_WHITESPACE) ||
DIFF_XDL_TST(options, IGNORE_WHITESPACE_CHANGE) ||
DIFF_XDL_TST(options, IGNORE_WHITESPACE_AT_EOL))
- DIFF_OPT_SET(options, DIFF_FROM_CONTENTS);
+ options->flags.diff_from_contents = 1;
else
- DIFF_OPT_CLR(options, DIFF_FROM_CONTENTS);
+ options->flags.diff_from_contents = 0;
- if (DIFF_OPT_TST(options, FIND_COPIES_HARDER))
+ if (options->flags.find_copies_harder)
options->detect_rename = DIFF_DETECT_COPY;
- if (!DIFF_OPT_TST(options, RELATIVE_NAME))
+ if (!options->flags.relative_name)
options->prefix = NULL;
if (options->prefix)
options->prefix_length = strlen(options->prefix);
DIFF_FORMAT_DIRSTAT |
DIFF_FORMAT_SUMMARY |
DIFF_FORMAT_CHECKDIFF))
- DIFF_OPT_SET(options, RECURSIVE);
+ options->flags.recursive = 1;
/*
* Also pickaxe would not work very well if you do not say recursive
*/
if (options->pickaxe)
- DIFF_OPT_SET(options, RECURSIVE);
+ options->flags.recursive = 1;
/*
* When patches are generated, submodules diffed against the work tree
* must be checked for dirtiness too so it can be shown in the output
*/
if (options->output_format & DIFF_FORMAT_PATCH)
- DIFF_OPT_SET(options, DIRTY_SUBMODULES);
+ options->flags.dirty_submodules = 1;
if (options->detect_rename && options->rename_limit < 0)
options->rename_limit = diff_rename_limit_default;
* to have found. It does not make sense not to return with
* exit code in such a case either.
*/
- if (DIFF_OPT_TST(options, QUICK)) {
+ if (options->flags.quick) {
options->output_format = DIFF_FORMAT_NO_OUTPUT;
- DIFF_OPT_SET(options, EXIT_WITH_STATUS);
+ options->flags.exit_with_status = 1;
}
options->diff_path_counter = 0;
- if (DIFF_OPT_TST(options, FOLLOW_RENAMES) && options->pathspec.nr != 1)
+ if (options->flags.follow_renames && options->pathspec.nr != 1)
die(_("--follow requires exactly one pathspec"));
if (!options->use_color || external_diff())
else if (starts_with(arg, "-C") || starts_with(arg, "--find-copies=") ||
!strcmp(arg, "--find-copies")) {
if (options->detect_rename == DIFF_DETECT_COPY)
- DIFF_OPT_SET(options, FIND_COPIES_HARDER);
+ options->flags.find_copies_harder = 1;
if ((options->rename_score = diff_scoreopt_parse(arg)) == -1)
return error("invalid argument to -C: %s", arg+2);
options->detect_rename = DIFF_DETECT_COPY;
else if (!strcmp(arg, "--no-renames"))
options->detect_rename = 0;
else if (!strcmp(arg, "--rename-empty"))
- DIFF_OPT_SET(options, RENAME_EMPTY);
+ options->flags.rename_empty = 1;
else if (!strcmp(arg, "--no-rename-empty"))
- DIFF_OPT_CLR(options, RENAME_EMPTY);
+ options->flags.rename_empty = 0;
else if (!strcmp(arg, "--relative"))
- DIFF_OPT_SET(options, RELATIVE_NAME);
+ options->flags.relative_name = 1;
else if (skip_prefix(arg, "--relative=", &arg)) {
- DIFF_OPT_SET(options, RELATIVE_NAME);
+ options->flags.relative_name = 1;
options->prefix = arg;
}
/* flags options */
else if (!strcmp(arg, "--binary")) {
enable_patch_output(&options->output_format);
- DIFF_OPT_SET(options, BINARY);
+ options->flags.binary = 1;
}
else if (!strcmp(arg, "--full-index"))
- DIFF_OPT_SET(options, FULL_INDEX);
+ options->flags.full_index = 1;
else if (!strcmp(arg, "-a") || !strcmp(arg, "--text"))
- DIFF_OPT_SET(options, TEXT);
+ options->flags.text = 1;
else if (!strcmp(arg, "-R"))
- DIFF_OPT_SET(options, REVERSE_DIFF);
+ options->flags.reverse_diff = 1;
else if (!strcmp(arg, "--find-copies-harder"))
- DIFF_OPT_SET(options, FIND_COPIES_HARDER);
+ options->flags.find_copies_harder = 1;
else if (!strcmp(arg, "--follow"))
- DIFF_OPT_SET(options, FOLLOW_RENAMES);
+ options->flags.follow_renames = 1;
else if (!strcmp(arg, "--no-follow")) {
- DIFF_OPT_CLR(options, FOLLOW_RENAMES);
- DIFF_OPT_CLR(options, DEFAULT_FOLLOW_RENAMES);
+ options->flags.follow_renames = 0;
+ options->flags.default_follow_renames = 0;
} else if (!strcmp(arg, "--color"))
options->use_color = 1;
else if (skip_prefix(arg, "--color=", &arg)) {
return argcount;
}
else if (!strcmp(arg, "--exit-code"))
- DIFF_OPT_SET(options, EXIT_WITH_STATUS);
+ options->flags.exit_with_status = 1;
else if (!strcmp(arg, "--quiet"))
- DIFF_OPT_SET(options, QUICK);
+ options->flags.quick = 1;
else if (!strcmp(arg, "--ext-diff"))
- DIFF_OPT_SET(options, ALLOW_EXTERNAL);
+ options->flags.allow_external = 1;
else if (!strcmp(arg, "--no-ext-diff"))
- DIFF_OPT_CLR(options, ALLOW_EXTERNAL);
- else if (!strcmp(arg, "--textconv"))
- DIFF_OPT_SET(options, ALLOW_TEXTCONV);
- else if (!strcmp(arg, "--no-textconv"))
- DIFF_OPT_CLR(options, ALLOW_TEXTCONV);
+ options->flags.allow_external = 0;
+ else if (!strcmp(arg, "--textconv")) {
+ options->flags.allow_textconv = 1;
+ options->flags.textconv_set_via_cmdline = 1;
+ } else if (!strcmp(arg, "--no-textconv"))
+ options->flags.allow_textconv = 0;
else if (!strcmp(arg, "--ignore-submodules")) {
- DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);
+ options->flags.override_submodule_config = 1;
handle_ignore_submodules_arg(options, "all");
} else if (skip_prefix(arg, "--ignore-submodules=", &arg)) {
- DIFF_OPT_SET(options, OVERRIDE_SUBMODULE_CONFIG);
+ options->flags.override_submodule_config = 1;
handle_ignore_submodules_arg(options, arg);
} else if (!strcmp(arg, "--submodule"))
options->submodule_format = DIFF_SUBMODULE_LOG;
&options->interhunkcontext))
;
else if (!strcmp(arg, "-W"))
- DIFF_OPT_SET(options, FUNCCONTEXT);
+ options->flags.funccontext = 1;
else if (!strcmp(arg, "--function-context"))
- DIFF_OPT_SET(options, FUNCCONTEXT);
+ options->flags.funccontext = 1;
else if (!strcmp(arg, "--no-function-context"))
- DIFF_OPT_CLR(options, FUNCCONTEXT);
+ options->flags.funccontext = 0;
else if ((argcount = parse_long_opt("output", av, &optarg))) {
char *path = prefix_filename(prefix, optarg);
options->file = xfopen(path, "w");
separator++;
}
- if (output_format & DIFF_FORMAT_DIRSTAT && DIFF_OPT_TST(options, DIRSTAT_BY_LINE))
+ if (output_format & DIFF_FORMAT_DIRSTAT && options->flags.dirstat_by_line)
dirstat_by_line = 1;
if (output_format & (DIFF_FORMAT_DIFFSTAT|DIFF_FORMAT_SHORTSTAT|DIFF_FORMAT_NUMSTAT) ||
}
if (output_format & DIFF_FORMAT_NO_OUTPUT &&
- DIFF_OPT_TST(options, EXIT_WITH_STATUS) &&
- DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) {
+ options->flags.exit_with_status &&
+ options->flags.diff_from_contents) {
/*
* run diff_flush_patch for the exit status. setting
* options->file to /dev/null should be safe, because we
* diff_addremove/diff_change does not set the bit when
* DIFF_FROM_CONTENTS is in effect (e.g. with -w).
*/
- if (DIFF_OPT_TST(options, DIFF_FROM_CONTENTS)) {
+ if (options->flags.diff_from_contents) {
if (options->found_changes)
- DIFF_OPT_SET(options, HAS_CHANGES);
+ options->flags.has_changes = 1;
else
- DIFF_OPT_CLR(options, HAS_CHANGES);
+ options->flags.has_changes = 0;
}
}
* to determine how many paths were dirty only
* due to stat info mismatch.
*/
- if (!DIFF_OPT_TST(diffopt, NO_INDEX))
+ if (!diffopt->flags.no_index)
diffopt->skip_stat_unmatch++;
diff_free_filepair(p);
}
diff_resolve_rename_copy();
diffcore_apply_filter(options);
- if (diff_queued_diff.nr && !DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
- DIFF_OPT_SET(options, HAS_CHANGES);
+ if (diff_queued_diff.nr && !options->flags.diff_from_contents)
+ options->flags.has_changes = 1;
else
- DIFF_OPT_CLR(options, HAS_CHANGES);
+ options->flags.has_changes = 0;
options->found_follow = 0;
}
diff_warn_rename_limit("diff.renameLimit",
opt->needed_rename_limit,
opt->degraded_cc_to_c);
- if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
+ if (!opt->flags.exit_with_status &&
!(opt->output_format & DIFF_FORMAT_CHECKDIFF))
return status;
- if (DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
- DIFF_OPT_TST(opt, HAS_CHANGES))
+ if (opt->flags.exit_with_status &&
+ opt->flags.has_changes)
result |= 01;
if ((opt->output_format & DIFF_FORMAT_CHECKDIFF) &&
- DIFF_OPT_TST(opt, CHECK_FAILED))
+ opt->flags.check_failed)
result |= 02;
return result;
}
int diff_can_quit_early(struct diff_options *opt)
{
- return (DIFF_OPT_TST(opt, QUICK) &&
+ return (opt->flags.quick &&
!opt->filter &&
- DIFF_OPT_TST(opt, HAS_CHANGES));
+ opt->flags.has_changes);
}
/*
static int is_submodule_ignored(const char *path, struct diff_options *options)
{
int ignored = 0;
- unsigned orig_flags = options->flags;
- if (!DIFF_OPT_TST(options, OVERRIDE_SUBMODULE_CONFIG))
+ struct diff_flags orig_flags = options->flags;
+ if (!options->flags.override_submodule_config)
set_diffopt_flags_from_submodule_config(options, path);
- if (DIFF_OPT_TST(options, IGNORE_SUBMODULES))
+ if (options->flags.ignore_submodules)
ignored = 1;
options->flags = orig_flags;
return ignored;
* Before the final output happens, they are pruned after
* merged into rename/copy pairs as appropriate.
*/
- if (DIFF_OPT_TST(options, REVERSE_DIFF))
+ if (options->flags.reverse_diff)
addremove = (addremove == '+' ? '-' :
addremove == '-' ? '+' : addremove);
}
diff_queue(&diff_queued_diff, one, two);
- if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
- DIFF_OPT_SET(options, HAS_CHANGES);
+ if (!options->flags.diff_from_contents)
+ options->flags.has_changes = 1;
}
void diff_change(struct diff_options *options,
is_submodule_ignored(concatpath, options))
return;
- if (DIFF_OPT_TST(options, REVERSE_DIFF)) {
+ if (options->flags.reverse_diff) {
SWAP(old_mode, new_mode);
SWAP(old_oid, new_oid);
SWAP(old_oid_valid, new_oid_valid);
two->dirty_submodule = new_dirty_submodule;
p = diff_queue(&diff_queued_diff, one, two);
- if (DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
+ if (options->flags.diff_from_contents)
return;
- if (DIFF_OPT_TST(options, QUICK) && options->skip_stat_unmatch &&
+ if (options->flags.quick && options->skip_stat_unmatch &&
!diff_filespec_check_stat_unmatch(p))
return;
- DIFF_OPT_SET(options, HAS_CHANGES);
+ options->flags.has_changes = 1;
}
struct diff_filepair *diff_unmerge(struct diff_options *options, const char *path)
* and because it is easy to find people oneline advising "git diff
* --exit-code" in hooks and other scripts, we do not do so.
*/
- if (!DIFF_OPT_TST(opt, EXIT_WITH_STATUS) &&
+ if (!opt->flags.exit_with_status &&
check_pager_config("diff") != 0)
setup_pager();
}
#define DIFF_FORMAT_CALLBACK 0x1000
-#define DIFF_OPT_RECURSIVE (1 << 0)
-#define DIFF_OPT_TREE_IN_RECURSIVE (1 << 1)
-#define DIFF_OPT_BINARY (1 << 2)
-#define DIFF_OPT_TEXT (1 << 3)
-#define DIFF_OPT_FULL_INDEX (1 << 4)
-#define DIFF_OPT_SILENT_ON_REMOVE (1 << 5)
-#define DIFF_OPT_FIND_COPIES_HARDER (1 << 6)
-#define DIFF_OPT_FOLLOW_RENAMES (1 << 7)
-#define DIFF_OPT_RENAME_EMPTY (1 << 8)
-/* (1 << 9) unused */
-#define DIFF_OPT_HAS_CHANGES (1 << 10)
-#define DIFF_OPT_QUICK (1 << 11)
-#define DIFF_OPT_NO_INDEX (1 << 12)
-#define DIFF_OPT_ALLOW_EXTERNAL (1 << 13)
-#define DIFF_OPT_EXIT_WITH_STATUS (1 << 14)
-#define DIFF_OPT_REVERSE_DIFF (1 << 15)
-#define DIFF_OPT_CHECK_FAILED (1 << 16)
-#define DIFF_OPT_RELATIVE_NAME (1 << 17)
-#define DIFF_OPT_IGNORE_SUBMODULES (1 << 18)
-#define DIFF_OPT_DIRSTAT_CUMULATIVE (1 << 19)
-#define DIFF_OPT_DIRSTAT_BY_FILE (1 << 20)
-#define DIFF_OPT_ALLOW_TEXTCONV (1 << 21)
-#define DIFF_OPT_DIFF_FROM_CONTENTS (1 << 22)
-#define DIFF_OPT_DIRTY_SUBMODULES (1 << 24)
-#define DIFF_OPT_IGNORE_UNTRACKED_IN_SUBMODULES (1 << 25)
-#define DIFF_OPT_IGNORE_DIRTY_SUBMODULES (1 << 26)
-#define DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG (1 << 27)
-#define DIFF_OPT_DIRSTAT_BY_LINE (1 << 28)
-#define DIFF_OPT_FUNCCONTEXT (1 << 29)
-#define DIFF_OPT_PICKAXE_IGNORE_CASE (1 << 30)
-#define DIFF_OPT_DEFAULT_FOLLOW_RENAMES (1U << 31)
-
-#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
-#define DIFF_OPT_TOUCHED(opts, flag) ((opts)->touched_flags & DIFF_OPT_##flag)
-#define DIFF_OPT_SET(opts, flag) (((opts)->flags |= DIFF_OPT_##flag),((opts)->touched_flags |= DIFF_OPT_##flag))
-#define DIFF_OPT_CLR(opts, flag) (((opts)->flags &= ~DIFF_OPT_##flag),((opts)->touched_flags |= DIFF_OPT_##flag))
+#define DIFF_FLAGS_INIT { 0 }
+struct diff_flags {
+ unsigned recursive:1;
+ unsigned tree_in_recursive:1;
+ unsigned binary:1;
+ unsigned text:1;
+ unsigned full_index:1;
+ unsigned silent_on_remove:1;
+ unsigned find_copies_harder:1;
+ unsigned follow_renames:1;
+ unsigned rename_empty:1;
+ unsigned has_changes:1;
+ unsigned quick:1;
+ unsigned no_index:1;
+ unsigned allow_external:1;
+ unsigned exit_with_status:1;
+ unsigned reverse_diff:1;
+ unsigned check_failed:1;
+ unsigned relative_name:1;
+ unsigned ignore_submodules:1;
+ unsigned dirstat_cumulative:1;
+ unsigned dirstat_by_file:1;
+ unsigned allow_textconv:1;
+ unsigned textconv_set_via_cmdline:1;
+ unsigned diff_from_contents:1;
+ unsigned dirty_submodules:1;
+ unsigned ignore_untracked_in_submodules:1;
+ unsigned ignore_dirty_submodules:1;
+ unsigned override_submodule_config:1;
+ unsigned dirstat_by_line:1;
+ unsigned funccontext:1;
+ unsigned pickaxe_ignore_case:1;
+ unsigned default_follow_renames:1;
+};
+
+static inline void diff_flags_or(struct diff_flags *a,
+ const struct diff_flags *b)
+{
+ char *tmp_a = (char *)a;
+ const char *tmp_b = (const char *)b;
+ int i;
+
+ for (i = 0; i < sizeof(struct diff_flags); i++)
+ tmp_a[i] |= tmp_b[i];
+}
+
#define DIFF_XDL_TST(opts, flag) ((opts)->xdl_opts & XDF_##flag)
#define DIFF_XDL_SET(opts, flag) ((opts)->xdl_opts |= XDF_##flag)
#define DIFF_XDL_CLR(opts, flag) ((opts)->xdl_opts &= ~XDF_##flag)
const char *a_prefix, *b_prefix;
const char *line_prefix;
size_t line_prefix_length;
- unsigned flags;
- unsigned touched_flags;
+ struct diff_flags flags;
/* diff-filter bits */
unsigned int filter;
pathchange_fn_t pathchange;
change_fn_t change;
add_remove_fn_t add_remove;
+ void *change_fn_data;
diff_format_fn_t format_callback;
void *format_callback_data;
diff_prefix_fn_t output_prefix;
extern void diff_no_index(struct rev_info *, int, const char **);
-extern int index_differs_from(const char *def, int diff_flags, int ita_invisible_in_index);
+extern int index_differs_from(const char *def, const struct diff_flags *flags,
+ int ita_invisible_in_index);
/*
* Fill the contents of the filespec "df", respecting any textconv defined by