diff options
author | Junio C Hamano <gitster@pobox.com> | 2007-09-14 18:23:01 -0700 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2007-09-14 18:23:01 -0700 |
commit | 04222b245c5e0d49242ef1ca995fadd5fa082cd3 (patch) | |
tree | d5206956b63447b10781bb899597f0f38c632a8b | |
parent | Merge branch 'jc/grep-c' (diff) | |
parent | Document ls-files --with-tree=<tree-ish> (diff) | |
download | tgif-04222b245c5e0d49242ef1ca995fadd5fa082cd3.tar.xz |
Merge branch 'jc/partial-remove'
* jc/partial-remove:
Document ls-files --with-tree=<tree-ish>
git-commit: partial commit of paths only removed from the index
git-commit: Allow partial commit of file removal.
-rw-r--r-- | Documentation/git-ls-files.txt | 9 | ||||
-rw-r--r-- | builtin-ls-files.c | 78 | ||||
-rwxr-xr-x | git-commit.sh | 7 | ||||
-rw-r--r-- | t/t7501-commit.sh | 32 |
4 files changed, 123 insertions, 3 deletions
diff --git a/Documentation/git-ls-files.txt b/Documentation/git-ls-files.txt index 997594549f..9e454f0a4d 100644 --- a/Documentation/git-ls-files.txt +++ b/Documentation/git-ls-files.txt @@ -15,7 +15,7 @@ SYNOPSIS [-x <pattern>|--exclude=<pattern>] [-X <file>|--exclude-from=<file>] [--exclude-per-directory=<file>] - [--error-unmatch] + [--error-unmatch] [--with-tree=<tree-ish>] [--full-name] [--abbrev] [--] [<file>]\* DESCRIPTION @@ -81,6 +81,13 @@ OPTIONS If any <file> does not appear in the index, treat this as an error (return 1). +--with-tree=<tree-ish>:: + When using --error-unmatch to expand the user supplied + <file> (i.e. path pattern) arguments to paths, pretend + that paths which were removed in the index since the + named <tree-ish> are still present. Using this option + with `-s` or `-u` options does not make any sense. + -t:: Identify the file status with the following tags (followed by a space) at the start of each line: diff --git a/builtin-ls-files.c b/builtin-ls-files.c index cce17b5ced..6c1db86e80 100644 --- a/builtin-ls-files.c +++ b/builtin-ls-files.c @@ -9,6 +9,7 @@ #include "quote.h" #include "dir.h" #include "builtin.h" +#include "tree.h" static int abbrev; static int show_deleted; @@ -26,6 +27,7 @@ static int prefix_offset; static const char **pathspec; static int error_unmatch; static char *ps_matched; +static const char *with_tree; static const char *tag_cached = ""; static const char *tag_unmerged = ""; @@ -247,6 +249,8 @@ static void show_files(struct dir_struct *dir, const char *prefix) continue; if (show_unmerged && !ce_stage(ce)) continue; + if (ce->ce_flags & htons(CE_UPDATE)) + continue; show_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce); } } @@ -332,6 +336,67 @@ static const char *verify_pathspec(const char *prefix) return real_prefix; } +/* + * Read the tree specified with --with-tree option + * (typically, HEAD) into stage #1 and then + * squash them down to stage #0. This is used for + * --error-unmatch to list and check the path patterns + * that were given from the command line. We are not + * going to write this index out. + */ +static void overlay_tree(const char *tree_name, const char *prefix) +{ + struct tree *tree; + unsigned char sha1[20]; + const char **match; + struct cache_entry *last_stage0 = NULL; + int i; + + if (get_sha1(tree_name, sha1)) + die("tree-ish %s not found.", tree_name); + tree = parse_tree_indirect(sha1); + if (!tree) + die("bad tree-ish %s", tree_name); + + /* Hoist the unmerged entries up to stage #3 to make room */ + for (i = 0; i < active_nr; i++) { + struct cache_entry *ce = active_cache[i]; + if (!ce_stage(ce)) + continue; + ce->ce_flags |= htons(CE_STAGEMASK); + } + + if (prefix) { + static const char *(matchbuf[2]); + matchbuf[0] = prefix; + matchbuf [1] = NULL; + match = matchbuf; + } else + match = NULL; + if (read_tree(tree, 1, match)) + die("unable to read tree entries %s", tree_name); + + for (i = 0; i < active_nr; i++) { + struct cache_entry *ce = active_cache[i]; + switch (ce_stage(ce)) { + case 0: + last_stage0 = ce; + /* fallthru */ + default: + continue; + case 1: + /* + * If there is stage #0 entry for this, we do not + * need to show it. We use CE_UPDATE bit to mark + * such an entry. + */ + if (last_stage0 && + !strcmp(last_stage0->name, ce->name)) + ce->ce_flags |= htons(CE_UPDATE); + } + } +} + static const char ls_files_usage[] = "git-ls-files [-z] [-t] [-v] (--[cached|deleted|others|stage|unmerged|killed|modified])* " "[ --ignored ] [--exclude=<pattern>] [--exclude-from=<file>] " @@ -452,6 +517,10 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) error_unmatch = 1; continue; } + if (!prefixcmp(arg, "--with-tree=")) { + with_tree = arg + 12; + continue; + } if (!prefixcmp(arg, "--abbrev=")) { abbrev = strtoul(arg+9, NULL, 10); if (abbrev && abbrev < MINIMUM_ABBREV) @@ -503,6 +572,15 @@ int cmd_ls_files(int argc, const char **argv, const char *prefix) read_cache(); if (prefix) prune_cache(prefix); + if (with_tree) { + /* + * Basic sanity check; show-stages and show-unmerged + * would not make any sense with this option. + */ + if (show_stage || show_unmerged) + die("ls-files --with-tree is incompatible with -s or -u"); + overlay_tree(with_tree, prefix); + } show_files(&dir, prefix); if (ps_matched) { diff --git a/git-commit.sh b/git-commit.sh index 41538f16e5..bb113e858b 100755 --- a/git-commit.sh +++ b/git-commit.sh @@ -379,8 +379,11 @@ t,) then refuse_partial "Cannot do a partial commit during a merge." fi + TMP_INDEX="$GIT_DIR/tmp-index$$" - commit_only=`git ls-files --error-unmatch -- "$@"` || exit + W= + test -z "$initial_commit" && W=--with-tree=HEAD + commit_only=`git ls-files --error-unmatch $W -- "$@"` || exit # Build a temporary index and update the real index # the same way. @@ -401,7 +404,7 @@ t,) ( GIT_INDEX_FILE="$NEXT_INDEX" export GIT_INDEX_FILE - git update-index --remove --stdin + git update-index --add --remove --stdin ) || exit ;; esac diff --git a/t/t7501-commit.sh b/t/t7501-commit.sh index 6bd3c9e3e0..b151b51a34 100644 --- a/t/t7501-commit.sh +++ b/t/t7501-commit.sh @@ -131,4 +131,36 @@ test_expect_success \ 'validate git-rev-list output.' \ 'diff current expected' +test_expect_success 'partial commit that involves removal (1)' ' + + git rm --cached file && + mv file elif && + git add elif && + git commit -m "Partial: add elif" elif && + git diff-tree --name-status HEAD^ HEAD >current && + echo "A elif" >expected && + diff expected current + +' + +test_expect_success 'partial commit that involves removal (2)' ' + + git commit -m "Partial: remove file" file && + git diff-tree --name-status HEAD^ HEAD >current && + echo "D file" >expected && + diff expected current + +' + +test_expect_success 'partial commit that involves removal (3)' ' + + git rm --cached elif && + echo elif >elif && + git commit -m "Partial: modify elif" elif && + git diff-tree --name-status HEAD^ HEAD >current && + echo "M elif" >expected && + diff expected current + +' + test_done |