git-ged 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+ Copyright (c) 2011, John Sumsion
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+ * Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ * Neither the name of the author nor the names of its contributors
13
+ may be used to endorse or promote products derived from this software
14
+ without specific prior written permission.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
+ POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,26 @@
1
+ NOTE: Much of the structure of this rubygem, including the README was copied
2
+ shamelessly from the grit gem, which seemed to be a very good example.
3
+ Including this license here is an attempt to give proper attribution.
4
+
5
+ (The MIT License)
6
+
7
+ Copyright (c) 2007-2009 Tom Preston-Werner
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining
10
+ a copy of this software and associated documentation files (the
11
+ 'Software'), to deal in the Software without restriction, including
12
+ without limitation the rights to use, copy, modify, merge, publish,
13
+ distribute, sublicense, and/or sell copies of the Software, and to
14
+ permit persons to whom the Software is furnished to do so, subject to
15
+ the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be
18
+ included in all copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
21
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,84 @@
1
+ git-ged
2
+ =======
3
+
4
+ * Status: experimental
5
+ * Author: John Sumsion
6
+ * Inspiration: Git, Tim Shadel
7
+
8
+ GEDCOM plugin for Git. As a `git` subcommand, git-ged lets you import and
9
+ manage GEDCOM files in a versioned, shareable way in a Git repository.
10
+
11
+ It is also possible to attach to other repositories and fetch related
12
+ genealogy from others who have imported it into their own repository.
13
+
14
+ As a library, git-ged lets you write programs that communicate genealogical
15
+ data in the git-ged repository layout.
16
+
17
+ As a repository implementation, git-ged also defines a repository
18
+ specification that, if adhered to by alternate implementations will render
19
+ all implementations data-compatible with each other.
20
+
21
+ The genealogical data format for persons and relationships is yet to be
22
+ decided. The first cut will be one that is largely one-to-one compatible
23
+ with GEDCOM 5.5. I fully expect to change the format before this
24
+ solidifies, and I'll use whatever is the commonly-accepted format.
25
+
26
+
27
+ ## Requirements
28
+
29
+ * git (http://git-scm.com) tested with 1.7.8
30
+ * grit gem (https://github.com/mojombo/grit) tested with 2.4.1
31
+
32
+
33
+ ## Install
34
+
35
+ Easiest install is via RubyGems:
36
+
37
+ $ gem install git-ged
38
+
39
+
40
+ ## Source
41
+
42
+ Git-ged's Git repo is available on GitHub, which can be browsed at:
43
+
44
+ https://github.com/jsumsiong/git-ged
45
+
46
+ and cloned with:
47
+
48
+ git clone https://github.com/jsumsiong/git-ged.git
49
+
50
+
51
+ ### Development
52
+
53
+ You will need these gems to get tests to pass:
54
+
55
+ * mocha
56
+
57
+
58
+ ### Contributing
59
+
60
+ If you'd like to hack on git-ged, follow these instructions. To get all of the
61
+ dependencies, install the gem first.
62
+
63
+ 1. Fork the project to your own account
64
+ 1. Clone down your fork
65
+ 1. Create a thoughtfully named topic branch to contain your change
66
+ 1. Hack away
67
+ 1. Add tests and make sure everything still passes by running `rake`
68
+ 1. If you are adding new functionality, document it in README.md
69
+ 1. Do not change the version number, I will do that on my end
70
+ 1. If necessary, rebase your commits into logical chunks, without errors
71
+ 1. Push the branch up to GitHub
72
+ 1. Send a pull request for your branch
73
+
74
+
75
+ ## Usage
76
+
77
+ TODO
78
+
79
+ Copyright
80
+ ---------
81
+
82
+ Copyright (c) 2011 John Sumsion. See LICENSE for details.
83
+
84
+ Portions Copyright (c) 2010 Tom Preston-Warner. See LICENSE.grit for details. Thanks to the github folks for the inspiring Grit gem.
@@ -0,0 +1,149 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'date'
4
+
5
+ #############################################################################
6
+ #
7
+ # Helper functions
8
+ #
9
+ #############################################################################
10
+
11
+ def name
12
+ @name ||= Dir['*.gemspec'].first.split('.').first
13
+ end
14
+
15
+ def version
16
+ line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
17
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
18
+ end
19
+
20
+ def date
21
+ Date.today.to_s
22
+ end
23
+
24
+ def rubyforge_project
25
+ name
26
+ end
27
+
28
+ def gemspec_file
29
+ "#{name}.gemspec"
30
+ end
31
+
32
+ def gem_file
33
+ "#{name}-#{version}.gem"
34
+ end
35
+
36
+ def replace_header(head, header_name)
37
+ head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
38
+ end
39
+
40
+ #############################################################################
41
+ #
42
+ # Standard tasks
43
+ #
44
+ #############################################################################
45
+
46
+ task :default => :test
47
+
48
+ require 'rake/testtask'
49
+ Rake::TestTask.new(:test) do |test|
50
+ test.libs << 'lib' << 'test' << '.'
51
+ test.pattern = 'test/**/test_*.rb'
52
+ test.verbose = true
53
+ end
54
+
55
+ desc "Generate RCov test coverage and open in your browser"
56
+ task :coverage do
57
+ require 'rcov'
58
+ sh "rm -fr coverage"
59
+ sh "rcov test/test_*.rb"
60
+ sh "open coverage/index.html"
61
+ end
62
+
63
+ require 'rdoc/task'
64
+ RDoc::Task.new do |rdoc|
65
+ rdoc.rdoc_dir = 'rdoc'
66
+ rdoc.title = "#{name} #{version}"
67
+ rdoc.rdoc_files.include('README*')
68
+ rdoc.rdoc_files.include('lib/**/*.rb')
69
+ end
70
+
71
+ desc "Open an irb session preloaded with this library"
72
+ task :console do
73
+ sh "irb -rubygems -r ./lib/#{name}.rb"
74
+ end
75
+
76
+ #############################################################################
77
+ #
78
+ # Custom tasks (add your own tasks here)
79
+ #
80
+ #############################################################################
81
+
82
+ desc "Upload site to Rubyforge"
83
+ task :site do
84
+ sh "scp -r doc/* jdsumsion@git-ged.rubyforge.org:/var/www/gforge-projects/git-ged"
85
+ end
86
+
87
+ #############################################################################
88
+ #
89
+ # Packaging tasks
90
+ #
91
+ #############################################################################
92
+
93
+ task :release => :build do
94
+ unless `git branch` =~ /^\* master$/
95
+ puts "You must be on the master branch to release!"
96
+ exit!
97
+ end
98
+ sh "git commit --allow-empty -a -m 'Release #{version}'"
99
+ sh "git tag v#{version}"
100
+ sh "git push origin master"
101
+ sh "git push origin v#{version}"
102
+ sh "gem push pkg/#{name}-#{version}.gem"
103
+ end
104
+
105
+ task :build => :gemspec do
106
+ sh "mkdir -p pkg"
107
+ sh "gem build #{gemspec_file}"
108
+ sh "mv #{gem_file} pkg"
109
+ end
110
+
111
+ task :gemspec => :validate do
112
+ # read spec file and split out manifest section
113
+ spec = File.read(gemspec_file)
114
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
115
+
116
+ # replace name version and date
117
+ replace_header(head, :name)
118
+ replace_header(head, :version)
119
+ replace_header(head, :date)
120
+ #comment this out if your rubyforge_project has a different name
121
+ replace_header(head, :rubyforge_project)
122
+
123
+ # determine file list from git ls-files
124
+ files = `git ls-files`.
125
+ split("\n").
126
+ sort.
127
+ reject { |file| file =~ /^\./ }.
128
+ reject { |file| file =~ /^(rdoc|pkg|test|experiments)/ }.
129
+ map { |file| " #{file}" }.
130
+ join("\n")
131
+
132
+ # piece file back together and write
133
+ manifest = " s.files = %w[\n#{files}\n ]\n"
134
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
135
+ File.open(gemspec_file, 'w') { |io| io.write(spec) }
136
+ puts "Updated #{gemspec_file}"
137
+ end
138
+
139
+ task :validate do
140
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
141
+ unless libfiles.empty?
142
+ puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
143
+ exit!
144
+ end
145
+ unless Dir['VERSION*'].empty?
146
+ puts "A `VERSION` file at root level violates Gem best practices."
147
+ exit!
148
+ end
149
+ end
data/TODO ADDED
@@ -0,0 +1,42 @@
1
+ Structure
2
+ - repo layout
3
+ - library
4
+ - commands
5
+
6
+ Bootstrapping
7
+ - integrate OptionParser (stdlib) and subcommand (gem) into git-ged commands
8
+ - patch gem-man to read README{,.md} in lieu of any explicit manpage (gem man rib)
9
+
10
+ - create licenses subdir with data licenses by short-name
11
+ - create templates area that refs/heads/master can be populated from during "git ged init"
12
+ - create git-ged command that invokes git-ged-*
13
+ - create lib/git-ged/init.rb that invokes git init + template population (normal or bare)
14
+ - create lib/git-ged/ingest.rb that copies a GEDCOM in and assigns permaname (refs/local/gedcoms)
15
+ - ingest one of Hannah's small GEDCOMs
16
+ - ingest one of Hannah's full GEDCOMs
17
+ - get rib-git-ged plugin working
18
+
19
+ - create living filter pipe for filtering GEDCOMs
20
+ - create lib/git-ged/import.rb that copies a GEDCOM from refs/{local=>heads}/gedcoms with living filter
21
+ - create person/family permaname generation strategies (_UUID or name/birth/death, parent permanames)
22
+ - create entity permaname+state link logic
23
+ - create lib/git-ged/import-person.rb that copies refs/heads/{gedcoms=>persons} (with living filter)
24
+ - create lib/git-ged/import-family.rb that copies refs/heads/{gedcoms=>families} (with living filter)
25
+ - import one of Hannah's GEDCOMs
26
+
27
+ - populate person/family => gedcom permaname+state links
28
+ - create ingest logic for dealing with the second ingest/import cycle on the same GEDCOM
29
+ - pick default person/family permaname generation logic based on whether the _UUIDs match up
30
+ - create local/gedcoms history based on
31
+
32
+
33
+ GUI:
34
+ shoes
35
+ EXE:
36
+ ocra
37
+ shoes (for GUIs)
38
+ Tools:
39
+ differ (ruby) for string diffs, edit distance style
40
+ datadiff (perl) annotated diff
41
+ datadiff (python) patch production
42
+
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'git-ged'
3
+ GitGed::CLI.new.run
@@ -0,0 +1,51 @@
1
+ Gem::Specification.new do |s|
2
+ s.specification_version = 2 if s.respond_to? :specification_version=
3
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
4
+ s.rubygems_version = '1.3.5'
5
+
6
+ $:.unshift(File.dirname(__FILE__))
7
+ require 'lib/git-ged'
8
+
9
+ s.name = 'git-ged'
10
+ s.version = GitGed::VERSION
11
+ s.date = '2012-01-05'
12
+ #s.rubyforge_project = 'git-ged'
13
+
14
+ s.summary = "GEDCOM plugin for Git"
15
+ s.description = "git-ged is a Ruby toolset for managing genealogical data (GEDCOM) inside a Git repository."
16
+
17
+ s.authors = ["John Sumsion"]
18
+ s.email = 'jdsumsion@gmail.com'
19
+ s.homepage = 'http://github.com/jdsumsion/git-ged'
20
+
21
+ s.require_paths = %w[lib]
22
+
23
+ s.rdoc_options = ["--charset=UTF-8"]
24
+ s.extra_rdoc_files = %w[README.md LICENSE LICENSE.grit TODO layout.txt]
25
+
26
+ s.add_dependency('grit', "~> 2.4.1")
27
+ s.add_dependency('subcommand', "~> 1.0.6")
28
+
29
+ s.add_development_dependency('mocha')
30
+
31
+ s.executables << 'git-ged'
32
+
33
+ # = MANIFEST =
34
+ s.files = %w[
35
+ LICENSE
36
+ LICENSE.grit
37
+ README.md
38
+ Rakefile
39
+ TODO
40
+ bin/git-ged
41
+ git-ged.gemspec
42
+ layout.txt
43
+ lib/git-ged.rb
44
+ lib/git-ged/cli.rb
45
+ lib/git-ged/init.rb
46
+ lib/git-ged/repo.rb
47
+ ]
48
+ # = MANIFEST =
49
+
50
+ s.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ }
51
+ end
@@ -0,0 +1,205 @@
1
+ GIT-GED CONCEPTS
2
+ ================
3
+
4
+ 1) Git-ged commands
5
+ [repo-level]
6
+ - Init: populates refs/heads/{master,content,intent} with README, LICENSE_DEFAULT, etc. as specified by user
7
+ - Clone: same as git clone
8
+ - Attach: same as git remote add, except that it allows the user to define the set of permanames of interest in the remote repo
9
+ - Fetch: same as git fetch, except that only permanames that the user currently has are fetched (along with refs/heads/master)
10
+ - Push: same as git push, except that only permanames that the remote repo has are updated
11
+ [entity-state]
12
+ - Intent: captures one-line user intent (separate from commit message)
13
+ - Ingest: populates refs/local/gedcoms/{permaname(s)} with a raw gedcom, adding new gedN files for permaname collisions
14
+ - Filter: performs living filter and populates refs/heads/gedcoms/{permaname}
15
+ - Import: creates any new persons/families and records import flag & new person/family permaname+state links in gedX.IMPORT
16
+ [interactive-use]
17
+ - Workspace: (subcommands: checkout, update, reset)
18
+ - checkout: grabs every specified person/family/gedcom permaname and puts it under the path repo/[persons|families|gedcoms]/{permaname} in a transient commit
19
+ - update: grabs the head of every specified person/family/gedcom permaname and puts it under a new refs/heads/workspace commit
20
+ - reset: warns if un-git-ged-committed refs/heads/workspace history, then nukes it and recreates a refs/heads/workspace commit with the same permanames as it had before
21
+ - Resolve: deals with multiple-record histories in a smart way (gedcoms/persons/families)
22
+ - Commit: creates commits on every separate permaname that has changed, using current intent as default commit subject plus details of all entities that changed
23
+
24
+ 2) Data Licenses
25
+ - Data license defaults to Creative Commons Attribution-ShareAlike 3.0 Unported
26
+ - Users can update license at repo/gedcom/record level
27
+ - Other common license options are easily specifiable
28
+ - Other Creative Commons options: CC-BY-3.0, CC-BY-NC-3.0, CC-BY-NC-SA-3.0, CC0-1.0
29
+ - Open Data Commons options: ODC-PDDL-1.0, ODC-BY-1.0, ODC-ODBL-1.0
30
+
31
+ 3) Gedcom
32
+ - all ingested gedcoms are stored verbatim under a "refs/local/gedcoms/{permaname}" ref
33
+ - all imported, living-filtered gedcoms are stored under a "refs/heads/gedcoms/{permaname}" ref
34
+ - there are multiple permanames for a gedcom:
35
+ - primary permaname for gedcom is the sha256 hash of "FILE & SUBM name[/email]"
36
+ - alternate permaname for gedcom is the sha256 hash of "FILE & DATE"
37
+ - alternate permaname for gedcom is the sha256 hash of "source path & SUBM name"
38
+ - alternate permaname for gedcom is the sha256 hash of all person _UUIDs, sorted alphanumerically
39
+ - keep your email, paths & filenames consistent to maximize permaname collisions
40
+ - copies the repo's LICENSE_DEFAULT unless overridden by the user at ingest time
41
+
42
+ 4) Person
43
+ - all imported persons are stored in a standard JSON format under a "refs/heads/persons/{permaname}" refs
44
+ - there are multiple permanames for a person:
45
+ - one is designated as primary, all permanames are annotated internally to the person by a versioned hash function (for easy recomputation)
46
+ - primary permaname for person defaults to the sha256 hash of the gedcom UID + sorted 'not-same-as' list
47
+ - alternate permaname for person is the sha256 hash of "<displayname>[ birthdate][ deathdate][ sorted 'not-same-as' list]" (can be designated as primary)
48
+ - alternate permaname for person is the sha256 hash of "<displayname> child of <permaname>" (for each parent, if there is no birth/death)
49
+ - other alternate permanames are definable, as long as the context-free code for computing them is included under refs/heads/code
50
+ - permanames based on "displayname" state should not change when the person's name is updated, they are designed to produce collisions based on import data
51
+ - although a person's primary permaname should remain largely constant, it can change for reasons of disambiguation (addition of a 'not-same-as' link)
52
+ - proper protection of living data
53
+ - all imported persons must be deceased and publicly-viewable, or the record will initially exist under the "refs/local/persons/..." refspace
54
+ - import is responsible for initially segmenting living vs. deceased, but after import the app is responsible for calculating living after edit and moving the record if necessary
55
+ - the same living check & segmentation logic that import uses will be available on-demand for apps to use after edit
56
+ - when a deceased record is made living, the deceased record's permaname gets a new commit that marks it as no-longer-visible (so that on subsequent fetch, other repositories can delete their records)
57
+ - includes optional "supersedes", "superseded-by", "derived-from", "same-as", and "not-same-as" link attributes
58
+ - see
59
+ - the "derived-from", "supersedes", and "superseded-by" link attributes allow for proper history-aware
60
+ linkage across permanames for tracing merge or other complicated person record derivation
61
+ - the "same-as" attribute is a loose identity link to an alternate history of a person
62
+ determined to be the same historical person, it is a hint that a merge or other record derivation may be useful in the future
63
+ - if the "not-same-as" attribute refers to a disconnected history of a *different* person under the same permaname,
64
+ it is best to change the permaname of each person this attribute is added to
65
+ - person merge is often not needed if the persons originated unchanged from the same gedcom
66
+ - person merge may be a "comes before/comes after" decision at import time
67
+ - person merge decisions can be deferred by storing two person entities under the same permaname
68
+ and letting the user make the before/after decision at a later time
69
+ - multiple persons can be stored under the same permaname under 'entity1'..'entityN' blob names
70
+ - copies the gedcom LICENSE if imported, copies the repo's LICENSE_DEFAULT if a newly-created person
71
+
72
+ 5) Family
73
+ - direct represenation of the GEDCOM family concept
74
+ - all imported families are stored in a standard JSON format under a "refs/heads/families/{permaname}" refs
75
+ - there are multiple permanames for a family:
76
+ - one is designated as primary, all permanames are annotated internally to the family by a versioned hash function (for easy recomputation)
77
+ - primary permaname for family defaults to the sha256 hash of the parents' primary permanames in alphanumeric order
78
+ - alternate permaname for family is the sha256 hash of "<displayname>[ displayname][ marriage date]" (if there is marriage information, displaynames ordered by primary permaname alphanumeric ordering of parents)
79
+ - other alternate permanames are definable, as long as the context-free code for computing them is included under refs/heads/code
80
+ - permanames based on "displayname" state should not change when the person's name is updated, they are designed to produce collisions based on import data
81
+ - primary permaname should change if the parents' permanames are modified, or if a parent is replaced with a different person
82
+ - includes person links for each person in each family position
83
+ - includes optional "supersedes", "superseded-by", "derived-from", "same-as", and "not-same-as" link attributes (like person)
84
+ - includes optional "prior-family" link attribute that tracks temporal household dissolution & recomposition
85
+ - family merge is often not needed if the family originated unchanged from the same gedcom
86
+ - family merge can be a "comes before/comes after" decision at import time, but is not as likely as person to fit this workflow
87
+ - family merge decisions can be deferred by storing two family entities under the same permaname
88
+ and letting the user make the before/after decision at a later time
89
+ - multiple families can be stored under the same permaname under 'entity1'..'entityN' blob names
90
+ - copies the gedcom LICENSE if imported, copies the repo's LICENSE_DEFAULT if a newly-created record
91
+
92
+ 6) Link Attribute
93
+ - link attributes always refer to BOTH primary permaname & state
94
+ - link attributes are encoded similar to XFN to start
95
+
96
+ 7) Merge Strategies
97
+ - merge comes in at least 4 flavors:
98
+ a) [import] alternate record storage + history linkage (recommended for automated import processes)
99
+ b) [post-import] "comes before/comes after" record replacement strategy for dealing with record reconciliation
100
+ c) [post-import] "pick correct values" record reconciliation strategy for dealing with partial truth from multiple sources (sets "derived-from" attribute(s))
101
+ d) [post-import] "disambiguation" record reconciliation strategy for separating records that are NOT the same person (sets "not-same-as" attribute(s))
102
+ - of course anyone can do anything they please to their records, but these strategies seem to deserve automation support
103
+
104
+ 8) Record deriviation tracing
105
+ - each of the following link attributes refers to another record via permaname+state reference
106
+ - "supersedes" indicates that a person (or family) is a full, identical replacement for another (used to be able to react to remote merges)
107
+ - "superseded-by" indicates that a static, not-to-be-further-edited person (or family) is left behind after having been merged into the canonical record (used to detect conflicts between local edits & remote merge or vice versa)
108
+ - "derived-from" indicates a clone-and-mutate to disambiguate a fully-merged record that represents two distinct historical persons or families (used to document manual record reconstruction efforts)
109
+ - "same-as" indicates a more-tentative-than-merge attempt at establishing identity to allow for disparate efforts to proceed before attempting a full merge
110
+ - "not-same-as" indicates a definitive statement that one person (or family) is NOT the same as another (used when extracting a half-merged entity that collided on a permaname)
111
+ - "prior-family" indicates that a family has many of the same members of a prior family, but temporal household dissolution & recomposition require two different families to be tracked (allows for "current family" computations based on a directed graph of prior-family edges)
112
+
113
+ 9) Deletion of Records
114
+ - person/family/gedcom delete comes in three flavors:
115
+ - "deref": I no longer care to track or maintain this person, if anyone has this person cloned, let them continue to maintain the record
116
+ - "hide": I want the record gone on any repo that follows mine, if they fetch from me, MAKE their record go away, dead-to-living transition uses this mechanism
117
+ - "delete": I want the record gone on any repo that follows mine, if they fetch from me, SUGGEST that their record go away
118
+ - "hide" and "delete" stubs hang around for a longish-but-limited amount of time, and there is a mechanism that automatically cleans them up every so often
119
+
120
+
121
+ GIT-GED REFS LAYOUT
122
+ ===================
123
+
124
+ refs/heads/*:
125
+ - stuff that can be cloned/forked
126
+ refs/local/*:
127
+ - dispensible stuff that is used for local import actions (not needed for collaboration)
128
+ - hidden stuff that should not be published on a clone/fork
129
+
130
+ refs/heads/master (fetchable, but non-mergeable):
131
+ - README: simple documentation of git-ged, with pointer to software to parse/use
132
+
133
+ refs/heads/content (fetchable, but non-mergeable):
134
+ - META: last version of git-ged that wrote
135
+ - INTENT: link to last intent
136
+ - ROOTS: links to various person roots
137
+ - ENTITIES: list of gedcom/person/family permaname+state links, may end up needing to be sharded for very large repos
138
+ - LICENSE_DEFAULT: default license for any new records added or imported into to this repository, defaults to Creative Commons Share-alike
139
+ - [non-versioned] CHANGELOG: contains up to last 100 edits performed, updated by git-ged commit
140
+
141
+ refs/heads/intent (fetchable, but non-mergeable):
142
+ - INTENT: stores the user's identity, single-line intent message, and date in the tree itself to capture "why"
143
+ - MUST exist: if no intent is explicitly stored, init/import/edit must stub one in that describes the largest-scope action being taken
144
+ - able to be as fine-grained and meticulous as the user wants to be, while allowing the user
145
+ the convenience of keeping the same intent over several small actions moving toward a large-time-scale goal
146
+ - able to generate a feed of intents from here
147
+
148
+ refs/heads/workspace (fetchable, but non-mergeable):
149
+ - non-history-preserving workspace tree for pulling a subset of records into a filesystem for edit
150
+
151
+ refs/heads/gedcoms/{permanames}:
152
+ - ged1: the living-filtered gedcom file renamed to a standard filename
153
+ - gedN: the living-filtered gedcom file renamed to a standard filename
154
+ - contains no living data, as a result of "ingest" followed by "import"
155
+ - gedX.META: link to intent; original file name & path; where/who the file came from; all permanames this gedcom was stored under (by permaname kind)
156
+ - gedX.LICENSE: license for use of this gedcom as a whole, copied to individual persons/families at import time
157
+
158
+ refs/local/gedcoms/{permanames}:
159
+ - *may* contain living data, populated without filtering by "ingest"
160
+ - ged1.ged: the raw gedcom file renamed to a standard filename
161
+ - gedN.ged: the raw gedcom file renamed to a standard filename
162
+ - pre-existing permanames get forwarded up to the new tree (collisions, yay!)
163
+ - new permanames get created, non-colliding permanames don't get forwarded (gc'd by some other mechanism)
164
+ - if the gedcom contains no living data, "import" can delete the refs/local refs
165
+ - can coexist with refs/heads/gedcoms/{permaname} for a while as documentation of exactly what got imported
166
+ - fetch/clone/fork does NOT include the original gedcom, just the "post-import" one (because only refs/heads comes along)
167
+
168
+ refs/heads/persons/{permanames}:
169
+ - entity1: the primary person in a standard JSON form
170
+ - entityN: alternate, not-yet-merged person records
171
+ - entityX.{format}: the primary person (or an alternate) in an alternate format
172
+ - entityX.META: link to intent; link(s) to gedcom permanames
173
+ - entityX.IDENTITY: optional "supersedes", "superseded-by", "derived-from", "same-as", and "not-same-as" link attributes; also any arbitrary XFNs to other permanames
174
+ - entityX.LICENSE: license for use of this person, copied from gedcom at import time, or from repo's LICENSE_DEFAULT at non-import-creation time
175
+ - commits on a person can easily be merged/fast-forwarded if history is shared and there are no textual conflicts
176
+ - commits on two persons of the same permaname that do NOT share history can undergo person merge
177
+ - merge commits set "supersedes" and "superseded-by" link attributes to allow post-merge traceability
178
+ - merging of META takes a "most recent intent / union" approach
179
+ - merging of IDENTITY takes a "union with conflict detection & manual resolution" approach
180
+ - merging of LICENSE takes the more restrictive license by default
181
+
182
+ refs/local/persons/{permanames}:
183
+ - non-public person record, behaves like person in every other respect
184
+ - typically a person record should exist under EITHER refs/local OR refs/heads
185
+ - if both exist, the refs/heads record is used exclusively
186
+
187
+ refs/heads/families/{permanames}:
188
+ - entity1: the primary family in a standard JSON form
189
+ - entityN: alternate, not-yet-merged family records
190
+ - entityX.{format}: the primary person (or an alternate) in an alternate format
191
+ - entityX.META: link to intent; link(s) to gedcom permanames
192
+ - entityX.IDENTITY: optional "prior-family", "derived-from", "supersedes", "superseded-by", "same-as", and "not-same-as" link attributes; also any arbitrary XFNs to other permanames
193
+ - entityX.LICENSE: license for use of this person, copied from gedcom at import time, or from repo's LICENSE_DEFAULT at non-import-creation time
194
+ - commits on a family can easily be merged/fast-forwarded if history is shared and there are no textual conflicts
195
+ - commits on two families of the same permaname that do NOT share history can undergo family merge
196
+ - merging of META takes a "most recent intent / union" approach
197
+ - merging of IDENTITY takes a "union with conflict detection & manual resolution" approach
198
+ - merging of LICENSE takes the more restrictive license by default
199
+
200
+ refs/local/families/{permanames}:
201
+ - non-public family record, behaves like person in every other respect
202
+ - typically a family record should exist under EITHER refs/local OR refs/heads
203
+ - if both exist, the refs/heads record is used exclusively
204
+
205
+
@@ -0,0 +1,53 @@
1
+ $:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
2
+
3
+ # core
4
+ require 'fileutils'
5
+ require 'time'
6
+
7
+ # stdlib
8
+ require 'logger'
9
+ require 'digest/sha1'
10
+
11
+ # third party
12
+ require 'grit'
13
+
14
+ # internal requires
15
+
16
+ # common libraries
17
+ require 'git-ged/repo'
18
+
19
+ # git-like repo interaction
20
+ require 'git-ged/cli'
21
+ require 'git-ged/init'
22
+
23
+ # internal support classes
24
+
25
+ module GitGed
26
+ VERSION = '0.0.2'
27
+
28
+ class << self
29
+
30
+ def version
31
+ VERSION
32
+ end
33
+
34
+ attr_accessor :debug
35
+
36
+ def grit_debug= onoff
37
+ Grit.debug = onoff
38
+ end
39
+
40
+ # The standard +logger+ for debugging git-ged calls - this defaults to a plain STDOUT logger
41
+ attr_accessor :logger
42
+
43
+ def log(str)
44
+ logger.debug { str }
45
+ end
46
+ end
47
+
48
+ self.debug = false
49
+ self.grit_debug = false
50
+
51
+ @logger ||= ::Logger.new(STDOUT)
52
+
53
+ end
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'git-ged'
4
+ require 'optparse'
5
+ require 'subcommand'
6
+
7
+ module GitGed
8
+ class CLI
9
+
10
+ include Subcommands
11
+
12
+ # patch until subcommand 1.0.7 comes out
13
+ attr_accessor :appname
14
+
15
+ def initialize
16
+ @options = {}
17
+
18
+ self.appname = "git ged"
19
+ global_options do |opts|
20
+ opts.banner = "Usage: #{appname} [options] [subcommand [options]]"
21
+ opts.separator ""
22
+ opts.separator "Global options are:"
23
+ opts.on("-v", "--[no-]verbose", "Show git-ged & grit debug") do |v|
24
+ GitGed.debug = v
25
+ GitGed.grit_debug = v
26
+ end
27
+ end
28
+ add_help_option
29
+
30
+ command :init do |opts|
31
+ opts.banner = "Usage: #{appname} init [-m msg] [repo]"
32
+ opts.description = "Initializes a new git-ged repo"
33
+ opts.separator ""
34
+ opts.separator "Options:"
35
+ opts.on "-m MESSAGE", "--message MESSAGE" do |msg|
36
+ @options[:message] = msg
37
+ end
38
+ end
39
+ end
40
+
41
+ def run
42
+ cmd = opt_parse()
43
+ if cmd
44
+ Repo.new.send cmd, ARGV, @options
45
+ else
46
+ puts global_options { |opts| opts }
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,12 @@
1
+ module GitGed
2
+ class Repo
3
+
4
+ ##
5
+ # Initializes a new git-ged repo
6
+ def init(args, options={})
7
+ system "git init -q #{args.map{|s| "\"#{s}\"" }.join(" ")}"
8
+ GitGed.log "Created new git-ged repo"
9
+ end
10
+
11
+ end
12
+ end
File without changes
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git-ged
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - John Sumsion
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-01-05 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: grit
16
+ requirement: &14236180 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.4.1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *14236180
25
+ - !ruby/object:Gem::Dependency
26
+ name: subcommand
27
+ requirement: &14235700 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.6
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *14235700
36
+ - !ruby/object:Gem::Dependency
37
+ name: mocha
38
+ requirement: &14235320 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *14235320
47
+ description: git-ged is a Ruby toolset for managing genealogical data (GEDCOM) inside
48
+ a Git repository.
49
+ email: jdsumsion@gmail.com
50
+ executables:
51
+ - git-ged
52
+ extensions: []
53
+ extra_rdoc_files:
54
+ - README.md
55
+ - LICENSE
56
+ - LICENSE.grit
57
+ - TODO
58
+ - layout.txt
59
+ files:
60
+ - LICENSE
61
+ - LICENSE.grit
62
+ - README.md
63
+ - Rakefile
64
+ - TODO
65
+ - bin/git-ged
66
+ - git-ged.gemspec
67
+ - layout.txt
68
+ - lib/git-ged.rb
69
+ - lib/git-ged/cli.rb
70
+ - lib/git-ged/init.rb
71
+ - lib/git-ged/repo.rb
72
+ homepage: http://github.com/jdsumsion/git-ged
73
+ licenses: []
74
+ post_install_message:
75
+ rdoc_options:
76
+ - --charset=UTF-8
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 1.8.11
94
+ signing_key:
95
+ specification_version: 2
96
+ summary: GEDCOM plugin for Git
97
+ test_files: []