Introduce "skip-worktree" bit in index, teach Git to get/set this bit
Detail about this bit is in Documentation/git-update-index.txt. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
dbd57f9968
commit
44a3691362
@ -107,6 +107,7 @@ OPTIONS
|
|||||||
Identify the file status with the following tags (followed by
|
Identify the file status with the following tags (followed by
|
||||||
a space) at the start of each line:
|
a space) at the start of each line:
|
||||||
H:: cached
|
H:: cached
|
||||||
|
S:: skip-worktree
|
||||||
M:: unmerged
|
M:: unmerged
|
||||||
R:: removed/deleted
|
R:: removed/deleted
|
||||||
C:: modified/changed
|
C:: modified/changed
|
||||||
|
@ -15,6 +15,7 @@ SYNOPSIS
|
|||||||
[--cacheinfo <mode> <object> <file>]\*
|
[--cacheinfo <mode> <object> <file>]\*
|
||||||
[--chmod=(+|-)x]
|
[--chmod=(+|-)x]
|
||||||
[--assume-unchanged | --no-assume-unchanged]
|
[--assume-unchanged | --no-assume-unchanged]
|
||||||
|
[--skip-worktree | --no-skip-worktree]
|
||||||
[--ignore-submodules]
|
[--ignore-submodules]
|
||||||
[--really-refresh] [--unresolve] [--again | -g]
|
[--really-refresh] [--unresolve] [--again | -g]
|
||||||
[--info-only] [--index-info]
|
[--info-only] [--index-info]
|
||||||
@ -99,6 +100,13 @@ in the index e.g. when merging in a commit;
|
|||||||
thus, in case the assumed-untracked file is changed upstream,
|
thus, in case the assumed-untracked file is changed upstream,
|
||||||
you will need to handle the situation manually.
|
you will need to handle the situation manually.
|
||||||
|
|
||||||
|
--skip-worktree::
|
||||||
|
--no-skip-worktree::
|
||||||
|
When one of these flags is specified, the object name recorded
|
||||||
|
for the paths are not updated. Instead, these options
|
||||||
|
set and unset the "skip-worktree" bit for the paths. See
|
||||||
|
section "Skip-worktree bit" below for more information.
|
||||||
|
|
||||||
-g::
|
-g::
|
||||||
--again::
|
--again::
|
||||||
Runs 'git-update-index' itself on the paths whose index
|
Runs 'git-update-index' itself on the paths whose index
|
||||||
@ -304,6 +312,27 @@ M foo.c
|
|||||||
<9> now it checks with lstat(2) and finds it has been changed.
|
<9> now it checks with lstat(2) and finds it has been changed.
|
||||||
|
|
||||||
|
|
||||||
|
Skip-worktree bit
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
Skip-worktree bit can be defined in one (long) sentence: When reading
|
||||||
|
an entry, if it is marked as skip-worktree, then Git pretends its
|
||||||
|
working directory version is up to date and read the index version
|
||||||
|
instead.
|
||||||
|
|
||||||
|
To elaborate, "reading" means checking for file existence, reading
|
||||||
|
file attributes or file content. The working directory version may be
|
||||||
|
present or absent. If present, its content may match against the index
|
||||||
|
version or not. Writing is not affected by this bit, content safety
|
||||||
|
is still first priority. Note that Git _can_ update working directory
|
||||||
|
file, that is marked skip-worktree, if it is safe to do so (i.e.
|
||||||
|
working directory version matches index version)
|
||||||
|
|
||||||
|
Although this bit looks similar to assume-unchanged bit, its goal is
|
||||||
|
different from assume-unchanged bit's. Skip-worktree also takes
|
||||||
|
precedence over assume-unchanged bit when both are set.
|
||||||
|
|
||||||
|
|
||||||
Configuration
|
Configuration
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ static const char *tag_removed = "";
|
|||||||
static const char *tag_other = "";
|
static const char *tag_other = "";
|
||||||
static const char *tag_killed = "";
|
static const char *tag_killed = "";
|
||||||
static const char *tag_modified = "";
|
static const char *tag_modified = "";
|
||||||
|
static const char *tag_skip_worktree = "";
|
||||||
|
|
||||||
static void show_dir_entry(const char *tag, struct dir_entry *ent)
|
static void show_dir_entry(const char *tag, struct dir_entry *ent)
|
||||||
{
|
{
|
||||||
@ -178,7 +179,8 @@ static void show_files(struct dir_struct *dir, const char *prefix)
|
|||||||
continue;
|
continue;
|
||||||
if (ce->ce_flags & CE_UPDATE)
|
if (ce->ce_flags & CE_UPDATE)
|
||||||
continue;
|
continue;
|
||||||
show_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce);
|
show_ce_entry(ce_stage(ce) ? tag_unmerged :
|
||||||
|
(ce_skip_worktree(ce) ? tag_skip_worktree : tag_cached), ce);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (show_deleted | show_modified) {
|
if (show_deleted | show_modified) {
|
||||||
@ -490,6 +492,7 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix)
|
|||||||
tag_modified = "C ";
|
tag_modified = "C ";
|
||||||
tag_other = "? ";
|
tag_other = "? ";
|
||||||
tag_killed = "K ";
|
tag_killed = "K ";
|
||||||
|
tag_skip_worktree = "S ";
|
||||||
}
|
}
|
||||||
if (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed)
|
if (show_modified || show_others || show_deleted || (dir.flags & DIR_SHOW_IGNORED) || show_killed)
|
||||||
require_work_tree = 1;
|
require_work_tree = 1;
|
||||||
|
@ -24,6 +24,7 @@ static int info_only;
|
|||||||
static int force_remove;
|
static int force_remove;
|
||||||
static int verbose;
|
static int verbose;
|
||||||
static int mark_valid_only;
|
static int mark_valid_only;
|
||||||
|
static int mark_skip_worktree_only;
|
||||||
#define MARK_FLAG 1
|
#define MARK_FLAG 1
|
||||||
#define UNMARK_FLAG 2
|
#define UNMARK_FLAG 2
|
||||||
|
|
||||||
@ -276,6 +277,11 @@ static void update_one(const char *path, const char *prefix, int prefix_length)
|
|||||||
die("Unable to mark file %s", path);
|
die("Unable to mark file %s", path);
|
||||||
goto free_return;
|
goto free_return;
|
||||||
}
|
}
|
||||||
|
if (mark_skip_worktree_only) {
|
||||||
|
if (mark_ce_flags(p, CE_SKIP_WORKTREE, mark_skip_worktree_only == MARK_FLAG))
|
||||||
|
die("Unable to mark file %s", path);
|
||||||
|
goto free_return;
|
||||||
|
}
|
||||||
|
|
||||||
if (force_remove) {
|
if (force_remove) {
|
||||||
if (remove_file_from_cache(p))
|
if (remove_file_from_cache(p))
|
||||||
@ -384,7 +390,7 @@ static void read_index_info(int line_termination)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char update_index_usage[] =
|
static const char update_index_usage[] =
|
||||||
"git update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again | -g] [--ignore-missing] [-z] [--verbose] [--] <file>...";
|
"git update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--really-refresh] [--cacheinfo] [--chmod=(+|-)x] [--assume-unchanged] [--skip-worktree|--no-skip-worktree] [--info-only] [--force-remove] [--stdin] [--index-info] [--unresolve] [--again | -g] [--ignore-missing] [-z] [--verbose] [--] <file>...";
|
||||||
|
|
||||||
static unsigned char head_sha1[20];
|
static unsigned char head_sha1[20];
|
||||||
static unsigned char merge_head_sha1[20];
|
static unsigned char merge_head_sha1[20];
|
||||||
@ -650,6 +656,14 @@ int cmd_update_index(int argc, const char **argv, const char *prefix)
|
|||||||
mark_valid_only = UNMARK_FLAG;
|
mark_valid_only = UNMARK_FLAG;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (!strcmp(path, "--no-skip-worktree")) {
|
||||||
|
mark_skip_worktree_only = UNMARK_FLAG;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(path, "--skip-worktree")) {
|
||||||
|
mark_skip_worktree_only = MARK_FLAG;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!strcmp(path, "--info-only")) {
|
if (!strcmp(path, "--info-only")) {
|
||||||
info_only = 1;
|
info_only = 1;
|
||||||
continue;
|
continue;
|
||||||
|
4
cache.h
4
cache.h
@ -181,10 +181,11 @@ struct cache_entry {
|
|||||||
* Extended on-disk flags
|
* Extended on-disk flags
|
||||||
*/
|
*/
|
||||||
#define CE_INTENT_TO_ADD 0x20000000
|
#define CE_INTENT_TO_ADD 0x20000000
|
||||||
|
#define CE_SKIP_WORKTREE 0x40000000
|
||||||
/* CE_EXTENDED2 is for future extension */
|
/* CE_EXTENDED2 is for future extension */
|
||||||
#define CE_EXTENDED2 0x80000000
|
#define CE_EXTENDED2 0x80000000
|
||||||
|
|
||||||
#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD)
|
#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD | CE_SKIP_WORKTREE)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Safeguard to avoid saving wrong flags:
|
* Safeguard to avoid saving wrong flags:
|
||||||
@ -233,6 +234,7 @@ static inline size_t ce_namelen(const struct cache_entry *ce)
|
|||||||
ondisk_cache_entry_size(ce_namelen(ce)))
|
ondisk_cache_entry_size(ce_namelen(ce)))
|
||||||
#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
|
#define ce_stage(ce) ((CE_STAGEMASK & (ce)->ce_flags) >> CE_STAGESHIFT)
|
||||||
#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
|
#define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE)
|
||||||
|
#define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE)
|
||||||
#define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
|
#define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE)
|
||||||
|
|
||||||
#define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
|
#define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644)
|
||||||
|
57
t/t2104-update-index-skip-worktree.sh
Executable file
57
t/t2104-update-index-skip-worktree.sh
Executable file
@ -0,0 +1,57 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (c) 2008 Nguyễn Thái Ngọc Duy
|
||||||
|
#
|
||||||
|
|
||||||
|
test_description='skip-worktree bit test'
|
||||||
|
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
cat >expect.full <<EOF
|
||||||
|
H 1
|
||||||
|
H 2
|
||||||
|
H sub/1
|
||||||
|
H sub/2
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat >expect.skip <<EOF
|
||||||
|
S 1
|
||||||
|
H 2
|
||||||
|
S sub/1
|
||||||
|
H sub/2
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_expect_success 'setup' '
|
||||||
|
mkdir sub &&
|
||||||
|
touch ./1 ./2 sub/1 sub/2 &&
|
||||||
|
git add 1 2 sub/1 sub/2 &&
|
||||||
|
git ls-files -t | test_cmp expect.full -
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'index is at version 2' '
|
||||||
|
test "$(test-index-version < .git/index)" = 2
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'update-index --skip-worktree' '
|
||||||
|
git update-index --skip-worktree 1 sub/1 &&
|
||||||
|
git ls-files -t | test_cmp expect.skip -
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'index is at version 3 after having some skip-worktree entries' '
|
||||||
|
test "$(test-index-version < .git/index)" = 3
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'ls-files -t' '
|
||||||
|
git ls-files -t | test_cmp expect.skip -
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'update-index --no-skip-worktree' '
|
||||||
|
git update-index --no-skip-worktree 1 sub/1 &&
|
||||||
|
git ls-files -t | test_cmp expect.full -
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'index version is back to 2 when there is no skip-worktree entry' '
|
||||||
|
test "$(test-index-version < .git/index)" = 2
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
Loading…
x
Reference in New Issue
Block a user