set of marks. If a mark is defined to different values,
the last file wins.
+ --import-marks-if-exists=<file>::
+ Like --import-marks but instead of erroring out, silently
+ skips the file if it does not exist.
+
--relative-marks::
After specifying --relative-marks= the paths specified
with --import-marks= and --export-marks= are relative
If an `LF` or double quote must be encoded into `<path>` shell-style
quoting should be used, e.g. `"path/with\n and \" in it"`.
-Additionally, in `040000` mode, `<path>` may also be an empty string
-(`""`) to specify the root of the tree.
-
The value of `<path>` must be in canonical form. That is it must not:
* contain an empty directory component (e.g. `foo//bar` is invalid),
* contain the special component `.` or `..` (e.g. `foo/./bar` and
`foo/../bar` are invalid).
+The root of the tree can be represented by an empty string as `<path>`.
+
It is recommended that `<path>` always be encoded using UTF-8.
`filedelete`
set previously or a full 40-byte SHA-1 of a Git blob, preexisting or
ready to be written.
-output uses the same format as `git cat-file --batch`:
+Output uses the same format as `git cat-file --batch`:
====
<sha1> SP 'blob' SP <size> LF
rather than wasting time on the early part of an import
before the unsupported command is detected.
+notes::
+ Require that the backend support the 'notemodify' (N)
+ subcommand to the 'commit' command.
+ Versions of fast-import not supporting notes will exit
+ with a message indicating so.
+
+
`option`
~~~~~~~~
Processes the specified option so that git fast-import behaves in a
static const char *export_marks_file;
static const char *import_marks_file;
static int import_marks_file_from_stream;
+ static int import_marks_file_ignore_missing;
static int relative_marks_paths;
/* Our last blob */
{
char line[512];
FILE *f = fopen(import_marks_file, "r");
- if (!f)
+ if (f)
+ ;
+ else if (import_marks_file_ignore_missing && errno == ENOENT)
+ return; /* Marks file does not exist */
+ else
die_errno("cannot read '%s'", import_marks_file);
while (fgets(line, sizeof(line), f)) {
uintmax_t mark;
p = uq.buf;
}
+ /* Git does not track empty, non-toplevel directories. */
+ if (S_ISDIR(mode) && !memcmp(sha1, EMPTY_TREE_SHA1_BIN, 20) && *p) {
+ tree_content_remove(&b->branch_tree, p, NULL);
+ return;
+ }
+
if (S_ISGITLINK(mode)) {
if (inline_data)
die("Git links cannot be specified 'inline': %s",
return strbuf_detach(&abs_path, NULL);
}
- static void option_import_marks(const char *marks, int from_stream)
+ static void option_import_marks(const char *marks,
+ int from_stream, int ignore_missing)
{
if (import_marks_file) {
if (from_stream)
import_marks_file = make_fast_import_path(marks);
safe_create_leading_directories_const(import_marks_file);
import_marks_file_from_stream = from_stream;
+ import_marks_file_ignore_missing = ignore_missing;
}
static void option_date_format(const char *fmt)
if (!prefixcmp(feature, "date-format=")) {
option_date_format(feature + 12);
} else if (!prefixcmp(feature, "import-marks=")) {
- option_import_marks(feature + 13, from_stream);
+ option_import_marks(feature + 13, from_stream, 0);
+ } else if (!prefixcmp(feature, "import-marks-if-exists=")) {
+ option_import_marks(feature + strlen("import-marks-if-exists="),
+ from_stream, 1);
} else if (!prefixcmp(feature, "export-marks=")) {
option_export_marks(feature + 13);
} else if (!strcmp(feature, "cat-blob")) {
relative_marks_paths = 0;
} else if (!prefixcmp(feature, "force")) {
force_update = 1;
+ } else if (!strcmp(feature, "notes")) {
+ ; /* do nothing; we have the feature */
} else {
return 0;
}
git diff-tree -C --find-copies-harder -r N4 N6 >actual &&
compare_diff_raw expect actual'
+test_expect_success \
+ 'N: delete directory by copying' \
+ 'cat >expect <<-\EOF &&
+ OBJID
+ :100644 000000 OBJID OBJID D foo/bar/qux
+ OBJID
+ :000000 100644 OBJID OBJID A foo/bar/baz
+ :000000 100644 OBJID OBJID A foo/bar/qux
+ EOF
+ empty_tree=$(git mktree </dev/null) &&
+ cat >input <<-INPUT_END &&
+ commit refs/heads/N-delete
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ collect data to be deleted
+ COMMIT
+
+ deleteall
+ M 100644 inline foo/bar/baz
+ data <<DATA_END
+ hello
+ DATA_END
+ C "foo/bar/baz" "foo/bar/qux"
+ C "foo/bar/baz" "foo/bar/quux/1"
+ C "foo/bar/baz" "foo/bar/quuux"
+ M 040000 $empty_tree foo/bar/quux
+ M 040000 $empty_tree foo/bar/quuux
+
+ commit refs/heads/N-delete
+ committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE
+ data <<COMMIT
+ delete subdirectory
+ COMMIT
+
+ M 040000 $empty_tree foo/bar/qux
+ INPUT_END
+ git fast-import <input &&
+ git rev-list N-delete |
+ git diff-tree -r --stdin --root --always |
+ sed -e "s/$_x40/OBJID/g" >actual &&
+ test_cmp expect actual'
+
test_expect_success \
'N: modify copied tree' \
'cat >expect <<-\EOF &&
'cat input | git fast-import --export-marks=other.marks &&
grep :1 other.marks'
+ test_expect_success 'R: catch typo in marks file name' '
+ test_must_fail git fast-import --import-marks=nonexistent.marks </dev/null &&
+ echo "feature import-marks=nonexistent.marks" |
+ test_must_fail git fast-import
+ '
+
+ test_expect_success 'R: import and output marks can be the same file' '
+ rm -f io.marks &&
+ blob=$(echo hi | git hash-object --stdin) &&
+ cat >expect <<-EOF &&
+ :1 $blob
+ :2 $blob
+ EOF
+ git fast-import --export-marks=io.marks <<-\EOF &&
+ blob
+ mark :1
+ data 3
+ hi
+
+ EOF
+ git fast-import --import-marks=io.marks --export-marks=io.marks <<-\EOF &&
+ blob
+ mark :2
+ data 3
+ hi
+
+ EOF
+ test_cmp expect io.marks
+ '
+
+ test_expect_success 'R: --import-marks=foo --output-marks=foo to create foo fails' '
+ rm -f io.marks &&
+ test_must_fail git fast-import --import-marks=io.marks --export-marks=io.marks <<-\EOF
+ blob
+ mark :1
+ data 3
+ hi
+
+ EOF
+ '
+
+ test_expect_success 'R: --import-marks-if-exists' '
+ rm -f io.marks &&
+ blob=$(echo hi | git hash-object --stdin) &&
+ echo ":1 $blob" >expect &&
+ git fast-import --import-marks-if-exists=io.marks --export-marks=io.marks <<-\EOF &&
+ blob
+ mark :1
+ data 3
+ hi
+
+ EOF
+ test_cmp expect io.marks
+ '
+
cat >input << EOF
feature import-marks=marks.out
feature export-marks=marks.new