gwt-import-gedcom¶
Turns a GEDCOM file (5.5.1 or 7) into a gwt-apply change list for review. It never writes to Gramps. Anyone who looks like a person already in your tree is held back until you say who they are, so importing a GEDCOM a second time, or a cousin's GEDCOM that overlaps yours, does not fill the tree with duplicates. Gramps Web's own import never merges anyone. It also audits a GEDCOM before you import it, and splits one into separate trees. Python 3.11+, standard library plus gwt-apply.
For a new, empty tree, use Gramps Web's own GEDCOM import instead: it keeps media and attributes this tool does not write. Run split first if the file holds two trees. Use gwt-import-gedcom when the tree already has people.
gwt apply --save-snapshot tree.json.gz # or a gwt check dump
gwt import-gedcom audit cousin.ged # what is wrong with the file, first
gwt import-gedcom cousin.ged --tree tree.json.gz --batch cousin-ana \
--out changes.jsonl --report report.json
gwt apply changes.jsonl --snapshot tree.json.gz # dry run, as always
--batch names the import. It is part of every key, with the first eight characters of the file's SHA-256 and the record's own id: ged-cousin-ana-1a2b3c4d-i12. The same file under the same batch gives the same keys, so a rerun after an apply is a skip. An edited file gives new keys, and its people go through the duplicate check again; they are never merged by key. --out, --report and --write-decisions are never overwritten without --force, must be three different files, and their folder must exist: the command checks that before it reads anything and exits 2.
People already in the tree¶
With --tree, each person in the file is compared with the tree the way gwt-apply's preflight compares them: the same full name, or the same first given name and first surname with a birth or baptism within two years, a parent in common or a spouse in common. A person who matches is not added. Their events, notes, citations and links wait with them, and the report lists them under namesakes:
{"xref": "@I3@", "name": "Diego García", "born": [1730], "namesake_of": ["I0007"],
"why": ["same name"], "decide": "--same @I3@=<one of I0007> or --different \"@I3@=<why another person>\""}
Decide each one and run again:
--same @I3@=I0007: that is the tree person. The file's families link to I0007, and nothing about I0007 is added: no second birth, no notes. Put new facts about them in with your own ops.--different "@I3@=baptised in another parish": another person. They are added withallow_namesake, your reason and the IDs they were compared with, so gwt-apply lets them through.
--same refuses an ID the snapshot does not have. I3 works as well as @I3@, here and in --root.
A real re-import can hold hundreds of people, so the decisions can go in a file, one per line, # for comments:
gwt import-gedcom cousin.ged --tree tree.json.gz --batch cousin-ana --out changes.jsonl --force \
--write-decisions decisions.txt # every held look-alike, each choice commented out
# edit decisions.txt: remove the # of one line per person
gwt import-gedcom cousin.ged --tree tree.json.gz --batch cousin-ana --out changes.jsonl --force \
--decisions decisions.txt
# @I3@ Diego García, born 1730 looks like I0007 (same name)
@I3@=I0007
# @I8@ Ana Ruiz looks like I0012 (same name)
@I8@!=born in another parish
Gramps Web's own GEDCOM import keeps each person's _UID as an attribute. A file person whose _UID is on a tree person is held as a look-alike of that person (why: same _UID), even when the tree has since changed the name. Each person this tool adds gets their _UID the same way (set_attribute), so the next import of a file from the same site finds them.
Two records of the same file that look alike (a grandfather and a grandson with one name) are kept apart, because the file keeps them apart. They get allow_namesake with the reason a separate record of the GEDCOM file, and the report lists them under file_namesakes. Two families of the file whose couples look alike get allow_new_couple the same way, listed under file_couples. Run audit first if you think the file has duplicates.
When the list would still be refused by gwt-apply's preflight (a couple that looks like a couple in the tree, after you said --different for both of them), the command prints why and exits 1. Saying --same for both parents makes that couple the tree's.
People who may be living are held unless --allow-living, by the toolkit's shared rule: no death or burial, and born less than 110 years ago or with nothing dated around them. A person with no given name (/García/ alone) is held too, and the family keeps the other parent.
What it writes¶
| GEDCOM | Change list |
|---|---|
INDI with NAME, SEX |
add_person; a second NAME becomes add_alternate_name (typed from its TYPE: married, aka, birth), and a _MARNM (a surname alone, or a whole name such as María /Gil/) an alternate name of type Married Name. Other NAME parts (NICK, NPFX...) are counted under not_imported |
_UID |
set_attribute _UID, and matched against the tree (above) |
BIRT, CHR, BAPM, DEAT, BURI, RESI, OCCU and the other events and facts, EVEN/FACT with TYPE |
add_event with date, place and description (an OCCU or RELI value goes in the description). A second birth or death goes in a note: gwt-apply keeps one of each. The same event twice is one event with the sources of both |
FAM with HUSB, WIFE, CHIL |
add_family; a child whose FAMC says PEDI adopted or foster gets link_child with that relation. A family with no parent left to add is skipped and reported |
PLAC |
add_place, one per level of the comma list, country first, typed from the header's PLAC.FORM when it has as many parts (Unknown otherwise). Each level is first looked for in the tree under the same parent, by name without case or accents: one match is used, several leave the event without a place and keep Place as written: ... in its description. MAP coordinates go on the last level. A one-level place (Villanueva) that is not at the top of the tree is looked for at any level: one match is used, several are ambiguous |
SOUR record, REPO |
add_source (title, author, publication), add_repository and link_repository with the call number |
SOUR citation with PAGE, QUAY, DATA |
add_citation, one per source, page, quality and date, attached to every person, family or event that cites it. QUAY 0-3 becomes confidence 0, 1, 3, 4 (2 when absent). One page cited with two qualities gets the quality in the second page text, as gwt-apply requires |
NOTE, SNOTE, citation TEXT |
add_note, a shared note attached to every record that points at it |
_FSFTID, _APID, EXID with TYPE |
set_external_id (FamilySearch, Ancestry, WikiTree, Geni, MyHeritage, Wikidata, or the TYPE as written). A FamilySearch id that is not one is reported, not written |
OBJE, SUBM, CHAN, anything else |
not imported; the report counts each under not_imported (an OBJE record once, and each link to one as INDI.OBJE or FAM.OBJE) |
Dates¶
GEDCOM dates become gwt-apply dates: 12 JAN 1850 is 1850-01-12, ABT, BEF, AFT, EST, CAL, BET ... AND and FROM ... TO keep their meaning. Julian (@#DJULIAN@, JULIAN) and French Republican (@#DFRENCH R@, FRENCH_R) dates keep their calendar and sort on the Gregorian day they fell on: @#DFRENCH R@ 1 VEND 12 is 1803-09-24. A dual year 1700/01 is read as 1701; one whose second year is not the next (1850/49) is kept as text. A range that ends before it starts (BET 1900 AND 1800) is kept as text too. An open FROM 1850 is read as after 1850 and TO 1850 as before it, and the report says so.
A date the tool cannot turn into a sortable date (31 FEB 1850, Easter 1850, a Hebrew date, a date before the year 1) is kept as text (text: 31 FEB 1850), never dropped and never guessed, and listed under date_problems with the reason. A date phrase alone, (during the war), is kept as text the same way.
Encodings¶
A byte-order mark wins, then the header's CHAR: UTF-8, UNICODE (UTF-16), ANSEL, ANSI (Windows-1252), ASCII, IBMPC, LATIN1. GEDCOM 7 is UTF-8. Files from some sites mix encodings, so each line is read on its own: a line that is UTF-8 in a Latin-1 or ANSEL file is read as UTF-8 (so María does not turn into MarÃa), and a line that is not valid in the declared encoding is read as UTF-8 when it can be, else as Windows-1252. A line of an ANSEL file with an accent before a space, a / or the end of the line cannot be ANSEL (ANSEL puts an accent before its letter), so it is read as Windows-1252: a Windows file labelled ANSEL is a common mislabel. A file that says UNICODE but has no NUL bytes is read as UTF-8, and UTF-16 with no byte-order mark is found by its NUL bytes. Each such line is listed with its number under the report's file, and by audit.
Some exporters cut a line in the middle of a character when they wrap it with CONC: the first byte of ó ends one line and the second starts the next. The reader puts the character back together before it decodes the lines, so the note reads León, not León. Some also write a raw line break inside a note instead of CONT: a line that is not a GEDCOM line, right after a text value (NOTE, TEXT, PAGE, TITL, AUTH, PUBL), is kept as a new line of that value. The import summary counts those lines, and audit lists them.
Audit¶
Writes nothing. Exits 0 whatever it finds, or 2 when the file cannot be read. It reports the version and the encoding (declared, as read, and every line read in another one), bare lines kept as text, records that look like the same person by the preflight's rules, dates that cannot be read, deaths before births, deaths past 110, children born when the mother was under 14 or over 52 or the father under 14 or over 85 (gwt-check's limits, so both tools give a family the same answer; 14 to 85 when the sex is not known), or after the parent died (nine months after, for a father), people linked to nobody, pointers to records that are not in the file, and records nothing points at.
Split¶
Writes trees/I1.ged and trees/I40.ged, in UTF-8. A root's tree is everyone who descends from one of the root's ancestors: the root, the root's ancestors, and every descendant of each of them. Every spouse of those people comes along as a stub: their own record and the family they share go in, their parents and other marriages do not. The sources, notes and repositories the kept records point at go in too. People in both trees (a couple whose roots you split) are in both files, and the summary says how many. The summary also says how many people are in no file at all (a spouse's own relatives, for one) and lists the first of them.
--root @I1@ on an import does the same cut and imports only that tree.
Record GEDCOMs¶
Some archive sites export one record as a GEDCOM 7 file: Open Archives gives one at https://www.openarchieven.nl/<archive>:<uuid>/gedcom. Such a file often holds only the names, sexes and family links of the people in the record, with no date: then everyone in it reads as maybe living and is held. Check the record, then import it with --allow-living, and cite the record with an add_citation of your own. When the file does carry the record's dated event and source, the people are dated by it and imported like any other file. Blank lines in these files are skipped.
Export¶
gwt-import-gedcom export writes a GEDCOM 5.5.1 file from an offline tree file — a gwt-check dump or a
gwt-apply snapshot, gzipped or not. It never touches Gramps: the file is the only input, so it always reads
the tree as the dump left it.
The export is for sharing a tree without sharing the people in it who may be alive. It leaves out what the
owner marked private, the same marks gwt-check public reports on, and its living rule is stricter than that
check's:
- A person who may be living (no death of their own, and born less than 110 years ago, or never dated with no
dated relative to bound them, or in a DNA association) is only a placeholder: the name "Living" and their
sex, never their real name, events, notes or citations. An undated person counts as living here;
gwt-check publicdoes not report them. - An object marked private never leaves the tree: it is not written, and references to it are dropped. A private parent disappears from their children's families; a family that loses every member is not written.
- A part of an object marked private is left out too: a private name (a private primary name is written as
"Private"), a private event reference, and a private child link, which drops both the family's
CHILand the child'sFAMC. - A family's events, notes and citations are written only when neither recorded spouse is living or private (judged before private members are dropped: a family that lost a spouse to the private filter keeps no events).
- A source is written only when an exported citation points at it: a source nobody can cite anymore never leaves, whatever its title says.
Free text is not anonymized. A note, a citation page, an event description or a source title written for a
dead person can still name a living one: «birth certificate of Bruno Sáez» cited on his grandmother's record
goes out as written. The report's text_naming_living lists, by Gramps ID, every exported note, citation,
event and source whose text holds a possibly living person's first name and whole surname. A namesake who died
matches too, so it is a list to read, not a verdict: mark what must not leave private, or edit it, and export
again. gwt-check public still covers a private person's name inside a visible text on the server.
--report writes who was anonymized, what was left out and text_naming_living, by Gramps ID, so a share can
be checked before it goes anywhere. The header's submitter name defaults to "Gramps Web Toolkit"; set it with
--submitter.
The export never invents: a date Gramps keeps as text only is written as a GEDCOM date phrase, never guessed,
and a date GEDCOM 5.5.1 cannot hold (a Persian or Islamic one, a range with no end, a modifier the writer does
not know) is a phrase from its text, or left out and counted in the report's dates_left_out. Gregorian,
Julian, French Republican and Hebrew dates keep their calendar. Media are not written (a GEDCOM points at files
that stay on the server), and event roles other than Primary, and Family on a family's own events, are not
written either: they belong to the other person's own record. XREFs are the Gramps IDs when they are unique
and fit GEDCOM's 20 characters, else a short form of the handle. CHAR is UTF-8, FORM LINEAGE-LINKED, and the
reader half of this same tool takes the file back with no problems. The file is for sharing, not for importing
back: a "Living" placeholder carries no dates, so the importer cannot tell it is living.
To export straight from the server instead, Gramps Web has its own GEDCOM exporter:
GET /api/exporters/ged/file?private=true&living=ReplaceCompleteName. It uses Gramps' own writer and its
probably_alive rule; this subcommand works offline from a dump, uses the toolkit's living rule and writes the
report.
Limits¶
-
An
OCCU,RELIorEDUCwith a value becomes an event of that type with the value as its description. Gramps Web's own importer makes some of them person attributes instead. -
Media (
OBJE) is counted, not imported: a GEDCOM holds file paths, not files. Add them withadd_media. - Hebrew, Islamic and other calendars are kept as text.
- A person matched with
--samegets no new facts from the file; add them with ops of your own. - The import holds the whole file in memory, which is fine for files of a few hundred thousand lines. People and places are matched through indexes, so a file of 10,000 people against a tree of 20,000 takes seconds, not minutes.