Introduction to Git –- Fall 2020
$ mkdir repository && cd repository
$ git init
Initialized empty Git repository in .../repository/.git/
$ find
digraph {
"repository/" -> ".git/"
".git/" -> "branches/"
".git/" -> "hooks/"
".git/" -> "info/ "
".git/" -> "objects/"
".git/" -> "refs/"
".git/" -> "config"
".git/" -> "description"
".git/" -> "HEAD"
"objects/" -> "info/"
"objects/" -> "pack/"
"refs/" -> "heads/"
"refs/" -> "tags/"
}
Most directories are empty and the files are not that interesting:
$ cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
$ cat .git/HEAD
ref: refs/heads/master
$ cat .git/description
Unnamed repository; edit this file 'description' to name the
repository.
Lets add some content:
$ echo "This file is very interesting" > file.txt
$ git add file.txt
$ git commit -m "This is the first commit"
[master (root-commit) 23b3ed5] This is the first commit
1 file changed, 1 insertion(+)
create mode 100644 file.txt
$ find
digraph {
"file.txt" [fontcolor=red]
"logs/" [fontcolor=red]
"master" [fontcolor=red]
"COMMIT_EDITMSG" [fontcolor=red]
"index" [fontcolor=red]
"23" [fontcolor=red]
"b3ed5b16..." [fontcolor=red]
"1a" [fontcolor=red]
"098a06bf..." [fontcolor=red]
"09" [fontcolor=red]
"c78e6e97..." [fontcolor=red]
"repository/" -> ".git/"
"repository/" -> "file.txt"
".git/" -> "branches/"
".git/" -> "hooks/"
".git/" -> "info/ "
".git/" -> "logs/"
".git/" -> "objects/"
".git/" -> "refs/"
".git/" -> "COMMIT_EDITMSG"
".git/" -> "config"
".git/" -> "description"
".git/" -> "HEAD"
".git/" -> "index"
"objects/" -> "23" -> "b3ed5b16..."
"objects/" -> "1a" -> "098a06bf..."
"objects/" -> "09" -> "c78e6e97..."
"objects/" -> "info/"
"objects/" -> "pack/"
"refs/" -> "heads/" -> "master"
"refs/" -> "tags/"
}
repository/
is a part of the working tree (or the workspace).
.git/
is not included. file.txt
. git add
and git commit
commands tell Git to care about file.txt
.
.git/objects/
. $ git hash-object file.txt
09c78e6e971ce9e3d69e75bcb3ffd5de05b0d59a
$ find
...
./.git/objects/09/c78e6e971ce9e3d69e75bcb3ffd5de05b0d59a
...
$ cp file.txt file2.txt
$ git hash-object file.txt file2.txt
09c78e6e971ce9e3d69e75bcb3ffd5de05b0d59a
09c78e6e971ce9e3d69e75bcb3ffd5de05b0d59a
git cat-file -p 09c78e6e
This file is very interesting
$ hexdump -C ./.git/objects/09/c78e6e97*
00000000 78 01 4b ca c9 4f 52 30 .... |x.K..OR06`...,VH|
00000010 cb cc 49 55 00 d2 65 a9 .... |..IU..e.E...y%.E|
00000020 a9 c5 25 99 79 e9 5c 00 .... |..%.y.\..I.3|
0000002c
$ git cat-file -t 09c78e6e
blob
$ git cat-file -p 09c78e6e
This file is very interesting
$ rm file.txt
$ find
....
./.git/objects/09/c78e6e971ce9e3d69e75bcb3ffd5de05b0d59a
....
$ git cat-file -p 09c78e6e971ce9e3d69e75bcb3ffd5de05b0d59a
This file is very interesting
$ git restore file.txt
$ cat file.txt
This file is very interesting
Let's take a second look at the repository:
digraph {
"file.txt"
"logs/"
"master"
"COMMIT_EDITMSG"
"index"
"23"
"b3ed5b16..." [fontcolor=red]
"1a"
"098a06bf..." [fontcolor=red]
"09"
"c78e6e97..."
"repository/" -> ".git/"
"repository/" -> "file.txt"
".git/" -> "branches/"
".git/" -> "hooks/"
".git/" -> "info/ "
".git/" -> "logs/"
".git/" -> "objects/"
".git/" -> "refs/"
".git/" -> "COMMIT_EDITMSG"
".git/" -> "config"
".git/" -> "description"
".git/" -> "HEAD"
".git/" -> "index"
"objects/" -> "23" -> "b3ed5b16..."
"objects/" -> "1a" -> "098a06bf..."
"objects/" -> "09" -> "c78e6e97..."
"objects/" -> "info/"
"objects/" -> "pack/"
"refs/" -> "heads/" -> "master"
"refs/" -> "tags/"
}
What are these two other objects?
$ git cat-file -t 1a098a06
tree
$ git cat-file -p 1a098a06
100644 blob 09c78e6e971ce9e3d69e75b.... file.txt
In this case, the tree has one level and one blob:
digraph {
first_blob [label="blob 09c78e6e...\nThis file is very interesting" shape=box]
"tree 1a098a06b...\nblob 09c78e6e.... file.txt" -> first_blob
}
Let's take a third look at the repository:
digraph {
"file.txt"
"logs/"
"master"
"COMMIT_EDITMSG"
"index"
"23"
"b3ed5b16..." [fontcolor=red]
"1a"
"098a06bf..."
"09"
"c78e6e97..."
"repository/" -> ".git/"
"repository/" -> "file.txt"
".git/" -> "branches/"
".git/" -> "hooks/"
".git/" -> "info/ "
".git/" -> "logs/"
".git/" -> "objects/"
".git/" -> "refs/"
".git/" -> "COMMIT_EDITMSG"
".git/" -> "config"
".git/" -> "description"
".git/" -> "HEAD"
".git/" -> "index"
"objects/" -> "23" -> "b3ed5b16..."
"objects/" -> "1a" -> "098a06bf..."
"objects/" -> "09" -> "c78e6e97..."
"objects/" -> "info/"
"objects/" -> "pack/"
"refs/" -> "heads/" -> "master"
"refs/" -> "tags/"
}
Just one object remains…
$ git cat-file -t 23b3ed5b
commit
$ git cat-file -p 23b3ed5b
tree 1a098a06bf0bcae9695238d9d5cb96345c00cacf
author Mirko Myllykoski <....@gmail.com> 1600867851 +0200
committer Mirko Myllykoski <....@gmail.com> 1600867851 +0200
This is the first commit
A commit stores the state of the project in a given point of time.
In this case, the commit points to a tree that has one level and one blob:
digraph {
first_blob [label="blob 09c78e6e...\nThis file is very interesting" shape=box]
file [label="file.txt\nThis file is very interesting" shape=box]
"commit 23b3ed5b1...\ntree 1a098a06b\nMirko Myll...\nThis is the first commit" -> "tree 1a098a06b...\nblob 09c78e6e.... file.txt" -> first_blob
"metadata" -> "repository/" -> file
}
In a more general case, the associated tree can contain several levels and multiple blobs:
digraph {
file1 [label="file1.txt" shape=box]
file2 [label="file2.txt" shape=box]
file3 [label="file3.txt" shape=box]
file4 [label="file4.txt" shape=box]
blob1 [label="blob 1" shape=box]
blob2 [label="blob 2" shape=box]
blob3 [label="blob 3" shape=box]
blob4 [label="blob 4" shape=box]
"commit 1" -> "tree 1"
"tree 1" -> blob1
"tree 1" -> blob2
"tree 1" -> "tree 2"
"tree 2" -> blob3
"tree 2" -> blob4
"metadata" -> "repository/"
"repository/" -> file1
"repository/" -> file2
"repository/" -> "directory/"
"directory/" -> file3
"directory/" -> file4
}
Let's see what else we can find…
digraph {
"file.txt"
"logs/"
"master"
"COMMIT_EDITMSG"
"index"
"23"
"b3ed5b16..."
"1a"
"098a06bf..."
"09"
"c78e6e97..."
"repository/" -> ".git/"
"repository/" -> "file.txt"
".git/" -> "branches/"
".git/" -> "hooks/"
".git/" -> "info/ "
".git/" -> "logs/"
".git/" -> "objects/"
".git/" -> "refs/"
".git/" -> "COMMIT_EDITMSG"
".git/" -> "config"
".git/" -> "description"
".git/" -> "HEAD"
".git/" -> "index"
"objects/" -> "23" -> "b3ed5b16..."
"objects/" -> "1a" -> "098a06bf..."
"objects/" -> "09" -> "c78e6e97..."
"objects/" -> "info/"
"objects/" -> "pack/"
"refs/" -> "heads/" -> "master"
"refs/" -> "tags/"
"HEAD" [fontcolor=red]
"refs/" [fontcolor=red]
"heads/" [fontcolor=red]
"master" [fontcolor=red]
}
HEAD
points (indirectly) to 23b3ed5b1
:$ cat ./.git/HEAD
ref: refs/heads/master
$ cat .git/refs/heads/master
23b3ed5b16095bb84b18d06734fdd614c8982841
digraph {
rankdir=LR
"HEAD" [shape=plaintext]
"master" [shape=plaintext]
first_blob [label="blob 09c78e6e...\nThis file is very interesting" shape=box]
"HEAD" -> "master" -> "commit\n23b3ed5b1..." -> "tree\n1a098a06b..." -> first_blob
}
HEAD
and master
are references.
HEAD
determines "most recent" commit.
HEAD
. master
is the current branch (more later). $ git tag first
$ find
digraph {
"file.txt"
"logs/"
"master"
"COMMIT_EDITMSG"
"index"
"23"
"b3ed5b16..."
"1a"
"098a06bf..."
"09"
"c78e6e97..."
"repository/" -> ".git/"
"repository/" -> "file.txt"
".git/" -> "branches/"
".git/" -> "hooks/"
".git/" -> "info/ "
".git/" -> "logs/"
".git/" -> "objects/"
".git/" -> "refs/"
".git/" -> "COMMIT_EDITMSG"
".git/" -> "config"
".git/" -> "description"
".git/" -> "HEAD"
".git/" -> "index"
"objects/" -> "23" -> "b3ed5b16..."
"objects/" -> "1a" -> "098a06bf..."
"objects/" -> "09" -> "c78e6e97..."
"objects/" -> "info/"
"objects/" -> "pack/"
"refs/" -> "heads/" -> "master"
"refs/" -> "tags/"
"tags/" -> first
"refs/" [fontcolor=red]
"tags/" [fontcolor=red]
"first" [fontcolor=red]
}
$ git rev-parse first
23b3ed5b16095bb84b18d06734fdd614c8982841
digraph {
rankdir=LR
"first" [shape=plaintext]
first_blob [label="blob 09c78e6e...\nThis file is very interesting" shape=box]
"first" -> "commit\n23b3ed5b1..." -> "tree\n1a098a06b..." -> first_blob
}
Let's repeat some of the earlier steps:
$ echo "More content" >> file.txt
$ git add file.txt
$ find
digraph {
"file.txt" [fontcolor=red]
"logs/"
"master"
"COMMIT_EDITMSG"
"index"
"23/"
"b3ed5b16..."
"1a/"
"098a06bf..."
"09/"
"c78e6e97..."
"3b/" [fontcolor=red]
"23ff0c41..." [fontcolor=red]
"repository/" -> ".git/"
"repository/" -> "file.txt"
".git/" -> "branches/"
".git/" -> "hooks/"
".git/" -> "info/ "
".git/" -> "logs/"
".git/" -> "objects/"
".git/" -> "refs/"
".git/" -> "COMMIT_EDITMSG"
".git/" -> "config"
".git/" -> "description"
".git/" -> "HEAD"
".git/" -> "index"
"objects/" -> "23/" -> "b3ed5b16..."
"objects/" -> "1a/" -> "098a06bf..."
"objects/" -> "09/" -> "c78e6e97..."
"objects/" -> "3b/" -> "23ff0c41..."
"objects/" -> "info/"
"objects/" -> "pack/"
"refs/" -> "heads/" -> "master"
"refs/" -> "tags/"
"tags/" -> first
}
$ git cat-file -p 3b23ff0c
This file is very interesting
More content
git add
command creates a blob that correspond to the update file.txt
file.
The index is a binary file:
digraph {
"file.txt"
"logs/"
"master"
"COMMIT_EDITMSG"
"index" [fontcolor=red]
"23/"
"b3ed5b16..."
"1a/"
"098a06bf..."
"09/"
"c78e6e97..."
"3b/"
"23ff0c41..."
"repository/" -> ".git/"
"repository/" -> "file.txt"
".git/" -> "branches/"
".git/" -> "hooks/"
".git/" -> "info/ "
".git/" -> "logs/"
".git/" -> "objects/"
".git/" -> "refs/"
".git/" -> "COMMIT_EDITMSG"
".git/" -> "config"
".git/" -> "description"
".git/" -> "HEAD"
".git/" -> "index"
"objects/" -> "23/" -> "b3ed5b16..."
"objects/" -> "1a/" -> "098a06bf..."
"objects/" -> "09/" -> "c78e6e97..."
"objects/" -> "3b/" -> "23ff0c41..."
"objects/" -> "info/"
"objects/" -> "pack/"
"refs/" -> "heads/" -> "master"
"refs/" -> "tags/"
"tags/" -> first
}
We can now turn the index to the next commit:
$ git commit -m "This is the second commit"
[master d3c6c63] This is the second commit
1 file changed, 1 insertion(+)
$ find
digraph {
"file.txt"
"logs/"
"master"
"COMMIT_EDITMSG"
"index"
"23/"
"b3ed5b16..."
"1a/"
"098a06bf..."
"09/"
"c78e6e97..."
"3b/"
"23ff0c41..."
"22/" [fontcolor=red]
"b5208beb..." [fontcolor=red]
"d3/" [fontcolor=red]
"c6c635fb..." [fontcolor=red]
"repository/" -> ".git/"
"repository/" -> "file.txt"
".git/" -> "branches/"
".git/" -> "hooks/"
".git/" -> "info/ "
".git/" -> "logs/"
".git/" -> "objects/"
".git/" -> "refs/"
".git/" -> "COMMIT_EDITMSG"
".git/" -> "config"
".git/" -> "description"
".git/" -> "HEAD"
".git/" -> "index"
"objects/" -> "23/" -> "b3ed5b16..."
"objects/" -> "1a/" -> "098a06bf..."
"objects/" -> "09/" -> "c78e6e97..."
"objects/" -> "3b/" -> "23ff0c41..."
"objects/" -> "22/" -> "b5208beb..."
"objects/" -> "d3/" -> "c6c635fb..."
"objects/" -> "info/"
"objects/" -> "pack/"
"refs/" -> "heads/" -> "master"
"refs/" -> "tags/"
"tags/" -> first
}
$ git cat-file -p 22b5208b
100644 blob 3b23ff0c411faf22c9253ed0.... file.txt
$ git cat-file -p d3c6c635
tree 22b5208bebacfcf745691f799b08df492b2a7da9
parent 23b3ed5b16095bb84b18d06734fdd614c8982841
author Mirko Myllykoski <mirko...> 1601228824 +0200
committer Mirko Myllykoski <mirko....> 1601228824 +0200
This is the second commit
parent 23b3ed5b16095bb84b18d06734fdd614c8982841
digraph {
rankdir=LR
second_commit [label="commit d3c6c635...\ntree 22b5208b\nparent 23b3ed5b1\nMirko Myll..\nThis is the second commit"]
first_commit [label="commit 23b3ed5b1...\ntree 1a098a06b\nMirko Myll...\nThis is the first commit"]
second_blob [label="blob 3b23ff0c\nThis file is very interesting\nMore content" shape=box]
first_blob [label="blob 09c78e6e...\nThis file is very interesting" shape=box]
second_commit -> "tree 22b5208b...\nblob 3b23ff0c file.txt" -> second_blob
first_commit -> "tree 1a098a06b...\nblob 09c78e6e.... file.txt" -> first_blob
second_commit -> first_commit
}
digraph {
rankdir=LR
"commit 1" -> "tree 1"
"commit 2" -> "tree 2"
"commit 2" -> "commit 1"
"commit 3" -> "tree 3"
"commit 3" -> "commit 2"
"commit 4" -> "tree 4"
"commit 4" -> "commit 3"
}
digraph {
rankdir=LR
"commit 2" -> "commit 1"
"commit 4" -> "commit 3"
"commit 4" -> "commit 2"
}
HEAD
and master
:$ cat .git/HEAD
ref: refs/heads/master
$ cat .git/refs/heads/master
d3c6c635fb44c7084797d47050bff7961853c19b
digraph {
rankdir=LR
"HEAD" [shape=plaintext]
"master" [shape=plaintext]
second_commit [label="commit d3c6c635...\ntree 22b5208b\nparent 23b3ed5b1\nMirko Myll..\nThis is the second commit"]
first_commit [label="commit 23b3ed5b1...\ntree 1a098a06b\nMirko Myll...\nThis is the first commit"]
second_commit -> first_commit
"HEAD" -> "master" -> second_commit
subgraph cluster_working_tree {
label="Working tree"
subgraph cluster_file {
label="file.txt"
"This file is very interesting\nMore content
" [shape=plain]
}
}
}
HEAD
. HEAD
to something else:$ git checkout 23b3ed5b
....
HEAD is now at 23b3ed5 This is the first commit
$ cat .git/HEAD
23b3ed5b16095bb84b18d06734fdd614c8982841
$ cat file.txt
This file is very interesting
digraph {
rankdir=LR
"HEAD" [shape=plaintext]
"master" [shape=plaintext]
second_commit [label="commit d3c6c635...\ntree 22b5208b\nparent 23b3ed5b1\nMirko Myll..\nThis is the second commit"]
first_commit [label="commit 23b3ed5b1...\ntree 1a098a06b\nMirko Myll...\nThis is the first commit"]
second_commit -> first_commit
"HEAD" -> first_commit
"master" -> second_commit
subgraph cluster_working_tree {
label="Working tree"
subgraph cluster_file {
label="file.txt"
"This file is very interesting
" [shape=plain]
}
}
}
$ echo "Different content" >> file.txt
$ git commit -a -m "This is the third commit"
[detached HEAD a118ae8] This is the third commit
1 file changed, 1 insertion(+)
$ git cat-file -p a118ae8c
tree 5fcc4f83fedf5a94cd773704bdb1ab2cdcadc6fd
parent 23b3ed5b16095bb84b18d06734fdd614c8982841
author Mirko Myllykoski <mirko....> 1601286412 +0200
committer Mirko Myllykoski <mirko....> 1601286412 +0200
This is the third commit
parent
points to the first commit:digraph {
rankdir=LR
third_commit [label="commit a118ae8c...\nparent 23b3ed5b1...\nThis is the third commit"]
first_commit [label="commit 23b3ed5b1...\nThis is the first commit"]
third_commit -> first_commit
}
digraph {
rankdir=LR
"HEAD" [shape=plaintext]
"master" [shape=plaintext]
third_commit [label="commit a118ae8c...\nThis is the third commit"]
second_commit [label="commit d3c6c635...\nThis is the second commit"]
first_commit [label="commit 23b3ed5b1...\nThis is the first commit"]
third_blob [label="blob ea5f4b8e\nThis file is very interesting\nDifferent content" shape=box]
second_blob [label="blob 3b23ff0c\nThis file is very interesting\nMore content" shape=box]
first_blob [label="blob 09c78e6e...\nThis file is very interesting" shape=box]
third_commit -> third_blob [style=dashed]
second_commit -> second_blob [style=dashed]
first_commit -> first_blob [style=dashed]
third_commit -> first_commit
second_commit -> first_commit
"HEAD" -> third_commit
"master" -> second_commit
subgraph cluster_working_tree {
label="Working tree"
subgraph cluster_file {
label="file.txt"
"This file is very interesting\nDifferent content
" [shape=plain]
}
}
}
We can give the second brach a name:
$ git checkout -b second_branch
Switched to a new branch 'second_branch'
$ cat .git/HEAD
ref: refs/heads/second_branch
$ cat .git/refs/heads/second_branch
a118ae8cda10a8f0a966ab7b9158b4a6d3b48cfc
digraph {
rankdir=LR
"HEAD" [shape=plaintext]
"master" [shape=plaintext]
"second_branch" [shape=plaintext]
third_commit [label="commit a118ae8c...\nThis is the third commit"]
second_commit [label="commit d3c6c635...\nThis is the second commit"]
first_commit [label="commit 23b3ed5b1...\nThis is the first commit"]
third_blob [label="blob ea5f4b8e\nThis file is very interesting\nDifferent content" shape=box]
second_blob [label="blob 3b23ff0c\nThis file is very interesting\nMore content" shape=box]
first_blob [label="blob 09c78e6e...\nThis file is very interesting" shape=box]
third_commit -> third_blob [style=dashed]
second_commit -> second_blob [style=dashed]
first_commit -> first_blob [style=dashed]
third_commit -> first_commit
second_commit -> first_commit
"HEAD" -> third_commit
"master" -> second_commit
"second_branch" -> third_commit
subgraph cluster_working_tree {
label="Working tree"
subgraph cluster_file {
label="file.txt"
"This file is very interesting\nDifferent content
" [shape=plain]
}
}
}
We can merge the two branches together:
$ git checkout master
$ git merge --no-ff second_branch
Auto-merging file.txt
CONFLICT (content): Merge conflict in file.txt
Automatic merge failed; fix conflicts and then commit the
result.
$ vim file.txt
We fix some conflicts at this point…
$ git add file.txt
$ git merge --continue
[master f0d7298] Merge branch 'second_branch'
The created commit has two parents:
$ git cat-file -p f0d72989
tree f63f3a4c548f5065cee598bed4ae189bd2c099d8
parent d3c6c635fb44c7084797d47050bff7961853c19b
parent a118ae8cda10a8f0a966ab7b9158b4a6d3b48cfc
author Mirko Myllykoski <mirko....> 1601288485 +0200
committer Mirko Myllykoski <mirko....> 1601288485 +0200
Merge branch 'second_branch'
Finally, the tree looks like follows:
digraph {
rankdir=LR
"HEAD" [shape=plaintext]
"master" [shape=plaintext]
"second_branch" [shape=plaintext]
fourth_commit [label="commit f0d72989...\nMerge branch 'second_branch'
"]
third_commit [label="commit a118ae8c...\nThis is the third commit"]
second_commit [label="commit d3c6c635...\nThis is the second commit"]
first_commit [label="commit 23b3ed5b1...\nThis is the first commit"]
fourth_blob [label="blob e51364b9\nThis file is very interesting\nMore content\nDifferent content" shape=box]
third_blob [label="blob ea5f4b8e\nThis file is very interesting\nDifferent content" shape=box]
second_blob [label="blob 3b23ff0c\nThis file is very interesting\nMore content" shape=box]
first_blob [label="blob 09c78e6e...\nThis file is very interesting" shape=box]
fourth_commit -> fourth_blob [style=dashed]
third_commit -> third_blob [style=dashed]
second_commit -> second_blob [style=dashed]
first_commit -> first_blob [style=dashed]
fourth_commit -> second_commit
fourth_commit -> third_commit
third_commit -> first_commit
second_commit -> first_commit
"HEAD" -> fourth_commit
"master" -> fourth_commit
"second_branch" -> third_commit
subgraph cluster_working_tree {
label="Working tree"
subgraph cluster_file {
label="file.txt"
"This file is very interesting\nMore content\nDifferent content
" [shape=plain]
}
}
}
We can always move back to any of the previous commits:
$ git checkout 23b3ed5b1
....
HEAD is now at 23b3ed5 This is the first commit
$ cat file.txt
This file is very interesting
digraph {
rankdir=LR
"HEAD" [shape=plaintext]
"master" [shape=plaintext]
"second_branch" [shape=plaintext]
fourth_commit [label="commit f0d72989...\nMerge branch 'second_branch'
"]
third_commit [label="commit a118ae8c...\nThis is the third commit"]
second_commit [label="commit d3c6c635...\nThis is the second commit"]
first_commit [label="commit 23b3ed5b1...\nThis is the first commit"]
fourth_blob [label="blob e51364b9\nThis file is very interesting\nMore content\nDifferent content" shape=box]
third_blob [label="blob ea5f4b8e\nThis file is very interesting\nDifferent content" shape=box]
second_blob [label="blob 3b23ff0c\nThis file is very interesting\nMore content" shape=box]
first_blob [label="blob 09c78e6e...\nThis file is very interesting" shape=box]
fourth_commit -> fourth_blob [style=dashed]
third_commit -> third_blob [style=dashed]
second_commit -> second_blob [style=dashed]
first_commit -> first_blob [style=dashed]
fourth_commit -> second_commit
fourth_commit -> third_commit
third_commit -> first_commit
second_commit -> first_commit
"HEAD" -> first_commit
"master" -> fourth_commit
"second_branch" -> third_commit
subgraph cluster_working_tree {
label="Working tree"
subgraph cluster_file {
label="file.txt"
"This file is very interesting" [shape=plain]
}
}
}
The end.
And idea: Try to play with different commands. See what happens to the .git/
directory.