git-ged 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []