aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/git-fast-import.txt36
-rw-r--r--fast-import.c13
-rwxr-xr-xt/t9300-fast-import.sh51
3 files changed, 94 insertions, 6 deletions
diff --git a/Documentation/git-fast-import.txt b/Documentation/git-fast-import.txt
index aeddd5e28..8bb5a0b36 100644
--- a/Documentation/git-fast-import.txt
+++ b/Documentation/git-fast-import.txt
@@ -269,7 +269,7 @@ change to the project.
data
('from' SP <committish> LF)?
('merge' SP <committish> LF)?
- (filemodify | filedelete)*
+ (filemodify | filedelete | filedeleteall)*
LF
....
@@ -292,10 +292,12 @@ commit message use a 0 length data. Commit messages are free-form
and are not interpreted by Git. Currently they must be encoded in
UTF-8, as gfi does not permit other encodings to be specified.
-Zero or more `filemodify` and `filedelete` commands may be
-included to update the contents of the branch prior to the commit.
-These commands can be supplied in any order, gfi is not sensitive
-to pathname or operation ordering.
+Zero or more `filemodify`, `filedelete` and `filedeleteall` commands
+may be included to update the contents of the branch prior to
+creating the commit. These commands may be supplied in any order.
+However it is recommended that a `filedeleteall` command preceed
+all `filemodify` commands in the same commit, as `filedeleteall`
+wipes the branch clean (see below).
`author`
^^^^^^^^
@@ -459,6 +461,30 @@ first non-empty directory or the root is reached.
here `<path>` is the complete path of the file to be removed.
See `filemodify` above for a detailed description of `<path>`.
+`filedeleteall`
+^^^^^^^^^^^^^^^
+Included in a `commit` command to remove all files (and also all
+directories) from the branch. This command resets the internal
+branch structure to have no files in it, allowing the frontend
+to subsequently add all interesting files from scratch.
+
+....
+ 'deleteall' LF
+....
+
+This command is extremely useful if the frontend does not know
+(or does not care to know) what files are currently on the branch,
+and therefore cannot generate the proper `filedelete` commands to
+update the content.
+
+Issuing a `filedeleteall` followed by the needed `filemodify`
+commands to set the correct content will produce the same results
+as sending only the needed `filemodify` and `filedelete` commands.
+The `filedeleteall` approach may however require gfi to use slightly
+more memory per active branch (less than 1 MiB for even most large
+projects); so frontends that can easily obtain only the affected
+paths for a commit are encouraged to do so.
+
`mark`
~~~~~~
Arranges for gfi to save a reference to the current object, allowing
diff --git a/fast-import.c b/fast-import.c
index c72c5c7a9..f80ddee2f 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -26,7 +26,8 @@ Format of STDIN stream:
lf;
commit_msg ::= data;
- file_change ::= file_del | file_obm | file_inm;
+ file_change ::= file_clr | file_del | file_obm | file_inm;
+ file_clr ::= 'deleteall' lf;
file_del ::= 'D' sp path_str lf;
file_obm ::= 'M' sp mode sp (hexsha1 | idnum) sp path_str lf;
file_inm ::= 'M' sp mode sp 'inline' sp path_str lf
@@ -1640,6 +1641,14 @@ static void file_change_d(struct branch *b)
free(p_uq);
}
+static void file_change_deleteall(struct branch *b)
+{
+ release_tree_content_recursive(b->branch_tree.tree);
+ hashclr(b->branch_tree.versions[0].sha1);
+ hashclr(b->branch_tree.versions[1].sha1);
+ load_tree(&b->branch_tree);
+}
+
static void cmd_from(struct branch *b)
{
const char *from;
@@ -1784,6 +1793,8 @@ static void cmd_new_commit(void)
file_change_m(b);
else if (!strncmp("D ", command_buf.buf, 2))
file_change_d(b);
+ else if (!strcmp("deleteall", command_buf.buf))
+ file_change_deleteall(b);
else
die("Unsupported file_change: %s", command_buf.buf);
read_next_command();
diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh
index 23a2ba78f..357a8724d 100755
--- a/t/t9300-fast-import.sh
+++ b/t/t9300-fast-import.sh
@@ -356,4 +356,55 @@ test_expect_success \
'test $old_branch != `git-rev-parse --verify branch^0` &&
test $old_branch = `git-rev-parse --verify branch@{1}`'
+###
+### series H
+###
+
+test_tick
+cat >input <<INPUT_END
+commit refs/heads/H
+committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+data <<COMMIT
+third
+COMMIT
+
+from refs/heads/branch^0
+M 644 inline i-will-die
+data <<EOF
+this file will never exist.
+EOF
+
+deleteall
+M 644 inline h/e/l/lo
+data <<EOF
+$file5_data
+EOF
+
+INPUT_END
+test_expect_success \
+ 'H: deletall, add 1' \
+ 'git-fast-import <input &&
+ git-whatchanged H'
+test_expect_success \
+ 'H: verify pack' \
+ 'for p in .git/objects/pack/*.pack;do git-verify-pack $p||exit;done'
+
+cat >expect <<EOF
+:100755 000000 f1fb5da718392694d0076d677d6d0e364c79b0bc 0000000000000000000000000000000000000000 D file2/newf
+:100644 000000 7123f7f44e39be127c5eb701e5968176ee9d78b1 0000000000000000000000000000000000000000 D file2/oldf
+:100755 000000 85df50785d62d3b05ab03d9cbf7e4a0b49449730 0000000000000000000000000000000000000000 D file4
+:100644 100644 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 fcf778cda181eaa1cbc9e9ce3a2e15ee9f9fe791 R100 newdir/interesting h/e/l/lo
+:100755 000000 e74b7d465e52746be2b4bae983670711e6e66657 0000000000000000000000000000000000000000 D newdir/exec.sh
+EOF
+git-diff-tree -M -r H^ H >actual
+test_expect_success \
+ 'H: validate old files removed, new files added' \
+ 'compare_diff_raw expect actual'
+
+echo "$file5_data" >expect
+test_expect_success \
+ 'H: verify file' \
+ 'git-cat-file blob H:h/e/l/lo >actual &&
+ diff -u expect actual'
+
test_done