Grence

Quick Start

A quick start guide to help you get started with Git Graph.

Let's create a simple Git repository and manage graph files with Git Graph. First, create a fresh directory.

mkdir quickstart
cd quickstart

Now, initialize a new Git repository.

git init

Install Git Graph

Normally, Git Graph is installed globally, but you can install it locally to this repository by using the --local flag.

git graph install --local

This command sets the graph drivers in the local repository's Git configuration.

Track Graph Files

After setting up the Git configuration, you can indicate which files Git Graph should manage with the following command:

git graph track "*.jsonl"

Here, *.jsonl represents the pattern for filenames you wish to track. For more details on this pattern syntax, refer to the Git Attributes documentation.

The quotation marks surrounding the pattern are essential to prevent the shell from expanding the glob pattern.

Commit the .gitattributes file

Now, commit the .gitattributes file to the repository.

git add .gitattributes
git commit -m "track *.jsonl files using Git Graph"

Create a graph file

Now, let's create a new simple PG-JSONL graph file named graph.jsonl.

/bin/cat <<'EOF' > graph.jsonl
{"type":"node","id":"101","labels":["person"],"properties":{"country":["United States"],"name":["Alice","Carol"]}}
{"type":"node","id":"102","labels":["person","student"],"properties":{"country":["Japan"],"name":["Bob"]}}
{"type":"edge","from":"101","to":"102","labels":["same_school","same_class"],"properties":{"since":[2012]},"undirected":true}
{"type":"edge","from":"101","to":"102","labels":["likes"],"properties":{"engaged":[false],"since":[2015]}}
EOF

This graph file is the same as the one in the Property Graph Exchange Format Specification.

We can then add and commit the graph file to the repository.

git add graph.jsonl
git commit -m "add graph.jsonl"

Now, let's edit the graph file and add a new node.

echo '{"type":"node","id":"103","labels":["person"],"properties":{"country":["Canada"],"name":["Dave"]}}' >> graph.jsonl

Before committing the changes, let's view the diff of the graph file.

$ git diff
diff --git a/graph.jsonl b/graph.jsonl
index 05e347b..2bc5243 100644
--- a/graph.jsonl
+++ b/graph.jsonl
@@ -29,6 +29,20 @@
           "Bob"
         ]
       }
+    },
+    {
+      "id": "103",
+      "labels": [
+        "person"
+      ],
+      "properties": {
+        "country": [
+          "Canada"
+        ],
+        "name": [
+          "Dave"
+        ]
+      }
     }
   ],
   "edges": [

Note that the graph file is in the PG-JSONL format, but the diff is displayed in JSON.

Now, instead of adding nodes, let's re-write the graph file with the original content with some changes.

/bin/cat <<'EOF' > graph.jsonl
{"type":"node","id":"101","labels":["person"],"properties":{"country":["USA"],"name":["Alice","Carol"]}}
{"type":"node","id":"102","labels":["person","student"],"properties":{"country":["Japan"],"name":["Bob"]}}
{"type":"edge","from":"101","to":"102","labels":["same_school","same_class"],"properties":{"since":[2012]},"undirected":true}
{"type":"edge","from":"101","to":"102","labels":["likes"],"properties":{"engaged":[true],"since":[2015]}}
EOF

If we re-run the git diff command, we can see the diff of the graph file.

$ git diff
diff --git a/graph.jsonl b/graph.jsonl
index 05e347b..44f76b0 100644
--- a/graph.jsonl
+++ b/graph.jsonl
@@ -7,7 +7,7 @@
       ],
       "properties": {
         "country": [
-          "United States"
+          "USA"
         ],
         "name": [
           "Alice",
@@ -53,7 +53,7 @@
       ],
       "properties": {
         "engaged": [
-          false
+          true
         ],
         "since": [
           2015

As you can see, Git Graph is using the git diff textconv option to display the graph files in JSON format, which is very useful because it keeps each element of the graph on a single line. However, this is not always sufficient for the semantic diffing feature.

In this example we can see that the "engaged" property is changed from false to true and the "country" property is changed from "United States" to "USA", but we don't know from the git diff output which nodes were changed. In some cases, you can't even tell if it's a node or an edge that was changed.

Git Graph diff driver is only useful for simple changes (e.g. adding a new node). For more complex changes, you should use the git graph difftool command.

Before committing the changes, let's create a new branch called merge-conflict.

git checkout -b merge-conflict

Now, commit the changes.

git add graph.jsonl
git commit -m "create the graph.jsonl file in the merge-conflict branch"

Switch back to the main branch.

git checkout main

Edit the graph file again.

/bin/cat <<'EOF' > graph.jsonl
{"type":"node","id":"101","labels":["person"],"properties":{"country":["U.S."],"name":["Alice","Carol"]}}
{"type":"node","id":"102","labels":["person","student"],"properties":{"country":["Japan"],"name":["Bob"]}}
{"type":"edge","from":"101","to":"102","labels":["same_school","same_class"],"properties":{"since":[2012]},"undirected":true}
{"type":"edge","from":"101","to":"102","labels":["likes"],"properties":{"engaged":[false],"since":[2015]}}
EOF

Add and commit the changes.

git add graph.jsonl
git commit -m "change graph.jsonl node 101 country property to U.S."

Merge the merge-conflict branch into the main branch. You will see a merge conflict.

$ git merge merge-conflict
 
Auto-merging graph.jsonl
CONFLICT (content): Merge conflict in graph.jsonl
Wrote 1 conflict(s) for graph.jsonl to graph.jsonl.conflicts.json
Automatic merge failed; fix conflicts and then commit the result.

The conflict is caused by the "country" property the node with id 101 has. Following the 3-way merge strategy, Git Graph sees a BASE version of "United States", a OURS version of "U.S.", and a THEIRS version of "USA" for the same property, and it doesn't know which one to keep.

You can see from the git merge output that a new file was created, graph.jsonl.conflicts.json, which contains the conflicts of the merge.

But, before resolving the conflicts, let's see how the difftool driver can show the deltas between the BASE, OURS, and THEIRS versions of the graph file.

$ git difftool HEAD~1 graph.jsonl # Get the delta between the BASE (HEAD~1 is the previous commit) and OURS (local file) versions.
 
Viewing (1/1): 'graph.jsonl'
Launch 'graph' [Y/n]? y
 
Modified Nodes:
  ~ node_101
    Property Modified: country: ["United States"] -> ["U.S."]
$ git difftool HEAD~1 merge-conflict # Get the delta between the BASE (HEAD~1 is the previous commit) and THEIRS (remote file) versions.
 
Viewing (1/1): 'graph.jsonl'
Launch 'graph' [Y/n]? y
 
Modified Nodes:
  ~ node_101
    Property Modified: country: ["United States"] -> ["USA"]
 
Modified Edges:
  ~ edge_101_102_directed
    Property Modified: engaged: [false] -> [true]

Although we can use the git difftool command to view the deltas between the BASE, OURS, and THEIRS versions of the graph file, the *.conflicts.json file is more useful for resolving the conflicts. Let's see it's content.

cat graph.jsonl.conflicts.json

Will output:

{
  "conflicts": [
    {
      "type": "node",
      "key": "node_101",
      "description": "Node with key node_101 modified in both branches, conflicting property 'country'.",
      "data": {
        "ours": {
          "type": "node",
          "id": "101",
          "labels": [
            "person"
          ],
          "properties": {
            "country": [
              "U.S."
            ],
            "name": [
              "Alice",
              "Carol"
            ]
          }
        },
        "theirs": {
          "type": "node",
          "id": "101",
          "labels": [
            "person"
          ],
          "properties": {
            "country": [
              "USA"
            ],
            "name": [
              "Alice",
              "Carol"
            ]
          }
        },
        "base": {
          "type": "node",
          "id": "101",
          "labels": [
            "person"
          ],
          "properties": {
            "country": [
              "United States"
            ],
            "name": [
              "Alice",
              "Carol"
            ]
          }
        }
      }
    }
  ]
}

The *.conflicts.json file is a JSON object with a conflicts array. Each conflict object contains the following properties:

  • type: The type of the conflict (node or edge)
  • key: The key of the graph element that is in conflict (node_101, edge_101_102_directed, etc.)
  • description: A natural language description of the conflict
  • data: Useful context for resolving the conflict with the BASE, OURS, and THEIRS versions of the graph element.

How is this guide?

On this page