2006-07-31 02:25:18 +08:00
|
|
|
#ifndef UNPACK_TREES_H
|
|
|
|
#define UNPACK_TREES_H
|
|
|
|
|
2018-08-16 01:54:05 +08:00
|
|
|
#include "cache.h"
|
2023-04-11 11:00:40 +08:00
|
|
|
#include "convert.h"
|
2020-07-29 04:23:39 +08:00
|
|
|
#include "strvec.h"
|
2018-08-16 01:54:05 +08:00
|
|
|
#include "string-list.h"
|
|
|
|
#include "tree-walk.h"
|
2010-11-16 03:52:19 +08:00
|
|
|
|
2020-02-01 19:39:22 +08:00
|
|
|
#define MAX_UNPACK_TREES MAX_TRAVERSE_TREES
|
2008-03-14 13:07:18 +08:00
|
|
|
|
2018-08-16 01:54:05 +08:00
|
|
|
struct cache_entry;
|
2006-07-31 02:25:18 +08:00
|
|
|
struct unpack_trees_options;
|
2019-09-04 02:04:56 +08:00
|
|
|
struct pattern_list;
|
2006-07-31 02:25:18 +08:00
|
|
|
|
2013-06-02 23:46:56 +08:00
|
|
|
typedef int (*merge_fn_t)(const struct cache_entry * const *src,
|
2008-03-07 10:12:28 +08:00
|
|
|
struct unpack_trees_options *options);
|
2006-07-31 02:25:18 +08:00
|
|
|
|
2010-08-11 16:38:04 +08:00
|
|
|
enum unpack_trees_error_types {
|
|
|
|
ERROR_WOULD_OVERWRITE = 0,
|
|
|
|
ERROR_NOT_UPTODATE_FILE,
|
|
|
|
ERROR_NOT_UPTODATE_DIR,
|
2021-12-09 13:08:27 +08:00
|
|
|
ERROR_CWD_IN_THE_WAY,
|
2010-08-11 16:38:06 +08:00
|
|
|
ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN,
|
|
|
|
ERROR_WOULD_LOSE_UNTRACKED_REMOVED,
|
2010-08-11 16:38:04 +08:00
|
|
|
ERROR_BIND_OVERLAP,
|
2017-03-15 05:46:39 +08:00
|
|
|
ERROR_WOULD_LOSE_SUBMODULE,
|
2020-03-27 08:48:56 +08:00
|
|
|
|
2020-03-27 08:48:57 +08:00
|
|
|
NB_UNPACK_TREES_ERROR_TYPES,
|
|
|
|
|
2020-03-27 08:48:56 +08:00
|
|
|
WARNING_SPARSE_NOT_UPTODATE_FILE,
|
2020-03-27 08:48:59 +08:00
|
|
|
WARNING_SPARSE_UNMERGED_FILE,
|
2020-03-27 08:48:56 +08:00
|
|
|
WARNING_SPARSE_ORPHANED_NOT_OVERWRITTEN,
|
|
|
|
|
2020-03-27 08:48:57 +08:00
|
|
|
NB_UNPACK_TREES_WARNING_TYPES,
|
2008-05-18 03:03:49 +08:00
|
|
|
};
|
|
|
|
|
2010-09-02 19:57:33 +08:00
|
|
|
/*
|
|
|
|
* Sets the list of user-friendly error messages to be used by the
|
2010-09-03 00:08:15 +08:00
|
|
|
* command "cmd" (either merge or checkout), and show_all_errors to 1.
|
2010-09-02 19:57:33 +08:00
|
|
|
*/
|
2010-09-02 19:57:34 +08:00
|
|
|
void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
|
|
|
|
const char *cmd);
|
2010-09-02 19:57:33 +08:00
|
|
|
|
2018-05-21 22:54:28 +08:00
|
|
|
/*
|
|
|
|
* Frees resources allocated by setup_unpack_trees_porcelain().
|
|
|
|
*/
|
|
|
|
void clear_unpack_trees_porcelain(struct unpack_trees_options *opts);
|
|
|
|
|
2021-09-28 00:33:44 +08:00
|
|
|
enum unpack_trees_reset_type {
|
|
|
|
UNPACK_RESET_NONE = 0, /* traditional "false" value; still valid */
|
|
|
|
UNPACK_RESET_INVALID = 1, /* "true" no longer valid; use below values */
|
|
|
|
UNPACK_RESET_PROTECT_UNTRACKED,
|
|
|
|
UNPACK_RESET_OVERWRITE_UNTRACKED
|
|
|
|
};
|
|
|
|
|
2006-07-31 02:25:18 +08:00
|
|
|
struct unpack_trees_options {
|
2021-09-28 00:33:44 +08:00
|
|
|
unsigned int merge,
|
2009-06-26 13:14:10 +08:00
|
|
|
update,
|
2021-09-28 00:33:41 +08:00
|
|
|
preserve_ignored,
|
2018-08-18 02:00:39 +08:00
|
|
|
clone,
|
2009-06-26 13:14:10 +08:00
|
|
|
index_only,
|
|
|
|
trivial_merges_only,
|
|
|
|
verbose_update,
|
|
|
|
aggressive,
|
|
|
|
skip_unmerged,
|
|
|
|
initial_checkout,
|
|
|
|
diff_index_cached,
|
2009-08-20 21:47:08 +08:00
|
|
|
skip_sparse_checkout,
|
2019-03-22 17:31:36 +08:00
|
|
|
quiet,
|
2011-06-01 01:06:44 +08:00
|
|
|
exiting_early,
|
2022-11-11 03:06:02 +08:00
|
|
|
dry_run,
|
|
|
|
skip_cache_tree_update;
|
2021-09-28 00:33:44 +08:00
|
|
|
enum unpack_trees_reset_type reset;
|
2006-07-31 02:25:18 +08:00
|
|
|
const char *prefix;
|
read-tree: add "--super-prefix" option, eliminate global
The "--super-prefix" option to "git" was initially added in [1] for
use with "ls-files"[2], and shortly thereafter "submodule--helper"[3]
and "grep"[4]. It wasn't until [5] that "read-tree" made use of it.
At the time [5] made sense, but since then we've made "ls-files"
recurse in-process in [6], "grep" in [7], and finally
"submodule--helper" in the preceding commits.
Let's also remove it from "read-tree", which allows us to remove the
option to "git" itself.
We can do this because the only remaining user of it is the submodule
API, which will now invoke "read-tree" with its new "--super-prefix"
option. It will only do so when the "submodule_move_head()" function
is called.
That "submodule_move_head()" function was then only invoked by
"read-tree" itself, but now rather than setting an environment
variable to pass "--super-prefix" between cmd_read_tree() we:
- Set a new "super_prefix" in "struct unpack_trees_options". The
"super_prefixed()" function in "unpack-trees.c" added in [5] will now
use this, rather than get_super_prefix() looking up the environment
variable we set earlier in the same process.
- Add the same field to the "struct checkout", which is only needed to
ferry the "super_prefix" in the "struct unpack_trees_options" all the
way down to the "entry.c" callers of "submodule_move_head()".
Those calls which used the super prefix all originated in
"cmd_read_tree()". The only other caller is the "unlink_entry()"
caller in "builtin/checkout.c", which now passes a "NULL".
1. 74866d75793 (git: make super-prefix option, 2016-10-07)
2. e77aa336f11 (ls-files: optionally recurse into submodules, 2016-10-07)
3. 89c86265576 (submodule helper: support super prefix, 2016-12-08)
4. 0281e487fd9 (grep: optionally recurse into submodules, 2016-12-16)
5. 3d415425c7b (unpack-trees: support super-prefix option, 2017-01-17)
6. 188dce131fa (ls-files: use repository object, 2017-06-22)
7. f9ee2fcdfa0 (grep: recurse in-process using 'struct repository', 2017-08-02)
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2022-12-20 20:39:56 +08:00
|
|
|
const char *super_prefix;
|
2011-08-30 03:31:06 +08:00
|
|
|
struct pathspec *pathspec;
|
2006-07-31 02:25:18 +08:00
|
|
|
merge_fn_t fn;
|
|
|
|
|
|
|
|
int head_idx;
|
|
|
|
|
2023-02-27 23:28:20 +08:00
|
|
|
struct cache_entry *df_conflict_entry; /* output only */
|
Make run_diff_index() use unpack_trees(), not read_tree()
A plain "git commit" would still run lstat() a lot more than necessary,
because wt_status_print() would cause the index to be repeatedly flushed
and re-read by wt_read_cache(), and that would cause the CE_UPTODATE bit
to be lost, resulting in the files in the index being lstat'ed three
times each.
The reason why wt-status.c ended up invalidating and re-reading the
cache multiple times was that it uses "run_diff_index()", which in turn
uses "read_tree()" to populate the index with *both* the old index and
the tree we want to compare against.
So this patch re-writes run_diff_index() to not use read_tree(), but
instead use "unpack_trees()" to diff the index to a tree. That, in
turn, means that we don't need to modify the index itself, which then
means that we don't need to invalidate it and re-read it!
This, together with the lstat() optimizations, means that "git commit"
on the kernel tree really only needs to lstat() the index entries once.
That noticeably cuts down on the cached timings.
Best time before:
[torvalds@woody linux]$ time git commit > /dev/null
real 0m0.399s
user 0m0.232s
sys 0m0.164s
Best time after:
[torvalds@woody linux]$ time git commit > /dev/null
real 0m0.254s
user 0m0.140s
sys 0m0.112s
so it's a noticeable improvement in addition to being a nice conceptual
cleanup (it's really not that pretty that "run_diff_index()" dirties the
index!)
Doing an "strace -c" on it also shows that as it cuts the number of
lstat() calls by two thirds, it goes from being lstat()-limited to being
limited by getdents() (which is the readdir system call):
Before:
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
60.69 0.000704 0 69230 31 lstat
23.62 0.000274 0 5522 getdents
8.36 0.000097 0 5508 2638 open
2.59 0.000030 0 2869 close
2.50 0.000029 0 274 write
1.47 0.000017 0 2844 fstat
After:
% time seconds usecs/call calls errors syscall
------ ----------- ----------- --------- --------- ----------------
45.17 0.000276 0 5522 getdents
26.51 0.000162 0 23112 31 lstat
19.80 0.000121 0 5503 2638 open
4.91 0.000030 0 2864 close
1.48 0.000020 0 274 write
1.34 0.000018 0 2844 fstat
...
It passes the test-suite for me, but this is another of one of those
really core functions, and certainly pretty subtle, so..
NOTE! The Linux lstat() system call is really quite cheap when everything
is cached, so the fact that this is quite noticeable on Linux is likely to
mean that it is *much* more noticeable on other operating systems. I bet
you'll see a much bigger performance improvement from this on Windows in
particular.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2008-01-20 09:27:12 +08:00
|
|
|
void *unpack_data;
|
2008-03-07 10:12:28 +08:00
|
|
|
|
|
|
|
struct index_state *dst_index;
|
2008-03-23 00:35:59 +08:00
|
|
|
struct index_state *src_index;
|
2009-08-20 21:47:08 +08:00
|
|
|
|
2020-03-17 02:05:04 +08:00
|
|
|
struct checkout_metadata meta;
|
2023-02-27 23:28:16 +08:00
|
|
|
|
|
|
|
struct unpack_trees_options_internal {
|
2023-02-27 23:28:17 +08:00
|
|
|
unsigned int nontrivial_merge,
|
2023-02-27 23:28:19 +08:00
|
|
|
show_all_errors,
|
|
|
|
debug_unpack; /* used by read-tree debugging */
|
2023-02-27 23:28:17 +08:00
|
|
|
|
2023-02-27 23:28:19 +08:00
|
|
|
int merge_size; /* used by read-tree debugging */
|
2023-02-27 23:28:17 +08:00
|
|
|
int cache_bottom;
|
|
|
|
const char *msgs[NB_UNPACK_TREES_WARNING_TYPES];
|
|
|
|
struct strvec msgs_to_free;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Store error messages in an array, each case
|
|
|
|
* corresponding to a error message type
|
|
|
|
*/
|
|
|
|
struct string_list unpack_rejects[NB_UNPACK_TREES_WARNING_TYPES];
|
|
|
|
|
|
|
|
struct index_state result;
|
|
|
|
|
2023-02-27 23:28:16 +08:00
|
|
|
struct pattern_list *pl;
|
|
|
|
struct dir_struct *dir;
|
|
|
|
} internal;
|
2006-07-31 02:25:18 +08:00
|
|
|
};
|
|
|
|
|
2018-08-14 00:14:25 +08:00
|
|
|
int unpack_trees(unsigned n, struct tree_desc *t,
|
|
|
|
struct unpack_trees_options *options);
|
2006-07-31 02:25:18 +08:00
|
|
|
|
unpack-trees: add a new update_sparsity() function
Previously, the only way to update the SKIP_WORKTREE bits for various
paths was invoking `git read-tree -mu HEAD` or calling the same code
that this codepath invoked. This however had a number of problems if
the index or working directory were not clean. First, let's consider
the case:
Flipping SKIP_WORKTREE -> !SKIP_WORKTREE (materializing files)
If the working tree was clean this was fine, but if there were files or
directories or symlinks or whatever already present at the given path
then the operation would abort with an error. Let's label this case
for later discussion:
A) There is an untracked path in the way
Now let's consider the opposite case:
Flipping !SKIP_WORKTREE -> SKIP_WORKTREE (removing files)
If the index and working tree was clean this was fine, but if there were
any unclean paths we would run into problems. There are three different
cases to consider:
B) The path is unmerged
C) The path has unstaged changes
D) The path has staged changes (differs from HEAD)
If any path fell into case B or C, then the whole operation would be
aborted with an error. With sparse-checkout, the whole operation would
be aborted for case D as well, but for its predecessor of using `git
read-tree -mu HEAD` directly, any paths that fell into case D would be
removed from the working copy and the index entry for that path would be
reset to match HEAD -- which looks and feels like data loss to users
(only a few are even aware to ask whether it can be recovered, and even
then it requires walking through loose objects trying to match up the
right ones).
Refusing to remove files that have unsaved user changes is good, but
refusing to work on any other paths is very problematic for users. If
the user is in the middle of a rebase or has made modifications to files
that bring in more dependencies, then for their build to work they need
to update the sparse paths. This logic has been preventing them from
doing so. Sometimes in response, the user will stage the files and
re-try, to no avail with sparse-checkout or to the horror of losing
their changes if they are using its predecessor of `git read-tree -mu
HEAD`.
Add a new update_sparsity() function which will not error out in any of
these cases but behaves as follows for the special cases:
A) Leave the file in the working copy alone, clear the SKIP_WORKTREE
bit, and print a warning (thus leaving the path in a state where
status will report the file as modified, which seems logical).
B) Do NOT mark this path as SKIP_WORKTREE, and leave it as unmerged.
C) Do NOT mark this path as SKIP_WORKTREE and print a warning about
the dirty path.
D) Mark the path as SKIP_WORKTREE, but do not revert the version
stored in the index to match HEAD; leave the contents alone.
I tried a different behavior for A (leave the SKIP_WORKTREE bit set),
but found it very surprising and counter-intuitive (e.g. the user sees
it is present along with all the other files in that directory, tries to
stage it, but git add ignores it since the SKIP_WORKTREE bit is set). A
& C seem like optimal behavior to me. B may be as well, though I wonder
if printing a warning would be an improvement. Some might be slightly
surprised by D at first, but given that it does the right thing with
`git commit` and even `git commit -a` (`git add` ignores entries that
are marked SKIP_WORKTREE and thus doesn't delete them, and `commit -a`
is similar), it seems logical to me.
Reviewed-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-27 08:48:52 +08:00
|
|
|
enum update_sparsity_result {
|
|
|
|
UPDATE_SPARSITY_SUCCESS = 0,
|
|
|
|
UPDATE_SPARSITY_WARNINGS = 1,
|
|
|
|
UPDATE_SPARSITY_INDEX_UPDATE_FAILURES = -1,
|
|
|
|
UPDATE_SPARSITY_WORKTREE_UPDATE_FAILURES = -2
|
|
|
|
};
|
|
|
|
|
2023-02-27 23:28:14 +08:00
|
|
|
enum update_sparsity_result update_sparsity(struct unpack_trees_options *options,
|
|
|
|
struct pattern_list *pl);
|
unpack-trees: add a new update_sparsity() function
Previously, the only way to update the SKIP_WORKTREE bits for various
paths was invoking `git read-tree -mu HEAD` or calling the same code
that this codepath invoked. This however had a number of problems if
the index or working directory were not clean. First, let's consider
the case:
Flipping SKIP_WORKTREE -> !SKIP_WORKTREE (materializing files)
If the working tree was clean this was fine, but if there were files or
directories or symlinks or whatever already present at the given path
then the operation would abort with an error. Let's label this case
for later discussion:
A) There is an untracked path in the way
Now let's consider the opposite case:
Flipping !SKIP_WORKTREE -> SKIP_WORKTREE (removing files)
If the index and working tree was clean this was fine, but if there were
any unclean paths we would run into problems. There are three different
cases to consider:
B) The path is unmerged
C) The path has unstaged changes
D) The path has staged changes (differs from HEAD)
If any path fell into case B or C, then the whole operation would be
aborted with an error. With sparse-checkout, the whole operation would
be aborted for case D as well, but for its predecessor of using `git
read-tree -mu HEAD` directly, any paths that fell into case D would be
removed from the working copy and the index entry for that path would be
reset to match HEAD -- which looks and feels like data loss to users
(only a few are even aware to ask whether it can be recovered, and even
then it requires walking through loose objects trying to match up the
right ones).
Refusing to remove files that have unsaved user changes is good, but
refusing to work on any other paths is very problematic for users. If
the user is in the middle of a rebase or has made modifications to files
that bring in more dependencies, then for their build to work they need
to update the sparse paths. This logic has been preventing them from
doing so. Sometimes in response, the user will stage the files and
re-try, to no avail with sparse-checkout or to the horror of losing
their changes if they are using its predecessor of `git read-tree -mu
HEAD`.
Add a new update_sparsity() function which will not error out in any of
these cases but behaves as follows for the special cases:
A) Leave the file in the working copy alone, clear the SKIP_WORKTREE
bit, and print a warning (thus leaving the path in a state where
status will report the file as modified, which seems logical).
B) Do NOT mark this path as SKIP_WORKTREE, and leave it as unmerged.
C) Do NOT mark this path as SKIP_WORKTREE and print a warning about
the dirty path.
D) Mark the path as SKIP_WORKTREE, but do not revert the version
stored in the index to match HEAD; leave the contents alone.
I tried a different behavior for A (leave the SKIP_WORKTREE bit set),
but found it very surprising and counter-intuitive (e.g. the user sees
it is present along with all the other files in that directory, tries to
stage it, but git add ignores it since the SKIP_WORKTREE bit is set). A
& C seem like optimal behavior to me. B may be as well, though I wonder
if printing a warning would be an improvement. Some might be slightly
surprised by D at first, but given that it does the right thing with
`git commit` and even `git commit -a` (`git add` ignores entries that
are marked SKIP_WORKTREE and thus doesn't delete them, and `commit -a`
is similar), it seems logical to me.
Reviewed-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-03-27 08:48:52 +08:00
|
|
|
|
2018-04-20 01:58:12 +08:00
|
|
|
int verify_uptodate(const struct cache_entry *ce,
|
|
|
|
struct unpack_trees_options *o);
|
|
|
|
|
2013-06-02 23:46:56 +08:00
|
|
|
int threeway_merge(const struct cache_entry * const *stages,
|
|
|
|
struct unpack_trees_options *o);
|
|
|
|
int twoway_merge(const struct cache_entry * const *src,
|
|
|
|
struct unpack_trees_options *o);
|
|
|
|
int bind_merge(const struct cache_entry * const *src,
|
|
|
|
struct unpack_trees_options *o);
|
|
|
|
int oneway_merge(const struct cache_entry * const *src,
|
|
|
|
struct unpack_trees_options *o);
|
2021-03-03 19:16:42 +08:00
|
|
|
int stash_worktree_untracked_merge(const struct cache_entry * const *src,
|
|
|
|
struct unpack_trees_options *o);
|
2006-07-31 02:26:15 +08:00
|
|
|
|
2006-07-31 02:25:18 +08:00
|
|
|
#endif
|