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.
This commit is contained in:
Junio C Hamano 2007-09-14 18:23:01 -07:00
commit 04222b245c
4 changed files with 123 additions and 3 deletions

View File

@ -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:

View File

@ -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) {

View File

@ -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

View File

@ -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