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:
commit
04222b245c
@ -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:
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user