[PYTHON] Einführung in Git (1) History-Speicher

Das Ziel dieser Geschichte

Einführung

Git ist eines der Versionsverwaltungssysteme. Was ist ein Versionsverwaltungssystem?

Es ist ein System mit Funktionen wie. Hier ist "Geschichte ändern"

Bezieht sich auf eine Reihe von Informationen, die in chronologischer Reihenfolge aufgezeichnet wurden.

Neben Git gibt es noch andere Versionsverwaltungssysteme wie CVS und Subversion, aber Git verfügt über die folgenden Funktionen.

Speicherung von Inhalten

Schauen wir uns zunächst an, wie Git als Content Vault funktioniert. Erstellen Sie zunächst ein leeres Git-Repository

% mkdir repo1
% cd repo1
% git init
Initialized empty Git repository in repo1/.git/

Erstellen Sie eine Datei mit dem Namen readme.txt, speichern Sie den Inhalt im Repository, überschreiben Sie die Datei mit anderen Inhalten und speichern Sie sie im Repository.

% echo aaa > readme.txt
% git hash-object -w readme.txt
72943a16fb2c8f38f9dde202b7a70ccc19c52f34
% echo bbb > readme.txt
% git hash-object -w readme.txt
f761ec192d9f0dca3329044b96ebdb12839dbff6
% rm -f readme.txt

Der Inhalt der gespeicherten Datei kann mithilfe der Zeichenfolge abgerufen werden, die angezeigt wird, wenn der Befehl hash-object als Schlüssel ausgeführt wird.

% git cat-file -p 72943a16fb2c8f38f9dde202b7a70ccc19c52f34 > readme.txt
% cat readme.txt
aaa
% git cat-file -p f761ec192d9f0dca3329044b96ebdb12839dbff6 > readme.txt
% cat readme.txt
bbb

Was ist zu beachten

Das ist. Wenn der unvollendete Teil möglich wird, ist es möglich, den Änderungsverlauf beizubehalten, aber bevor ich ihn betrachte, ist "etwas, das ich nicht verstehe" der SHA1-Hashwert des Dateiinhalts (+ α). Stellen wir sicher, dass es das gibt.

hash-object.py


import hashlib
import sys

if len(sys.argv) != 2:
    print("usage: %s file" % sys.argv[0])
    sys.exit(-1)

try:
    f = open(sys.argv[1])
except Exception:
    print("open %s failed" % sys.argv[1])
    sys.exit(-1)

data = f.read()
sha1 = hashlib.sha1("blob %d" % len(data) + "\0" + data).hexdigest()
print(sha1)

Dieses Python-Programm

Berechnet den SHA1-Hashwert der Verkettung und gibt seine hexadezimale Darstellung aus. Wenn ich es tatsächlich für die beiden oben genannten Inhalte verwende,

% echo aaa | python hash-object.py /dev/stdin
72943a16fb2c8f38f9dde202b7a70ccc19c52f34
% echo bbb | python hash-object.py /dev/stdin
f761ec192d9f0dca3329044b96ebdb12839dbff6

Und Sie können sehen, dass das Berechnungsergebnis mit dem Schlüssel übereinstimmt, der zum früheren Speichern des Inhalts verwendet wurde (der Inhalt wird unter Verwendung des SHA1-Hashwerts des Dateiinhalts + α als Schlüssel gespeichert). Das Speicherziel im Inhaltsrepository ist übrigens

% find .git/objects -type f
.git/objects/72/943a16fb2c8f38f9dde202b7a70ccc19c52f34
.git/objects/f7/61ec192d9f0dca3329044b96ebdb12839dbff6

Der SHA1-Hashwert ist die Verkettung von Verzeichnisname und Dateiname. Wenn Sie den SHA1-Wert dieser Dateien selbst verwenden

% sha1sum `find .git/objects -type f`
cf6e4f80cfae36e20ae7eb1a90919ca48f59514b  .git/objects/72/943a16fb2c8f38f9dde202b7a70ccc19c52f34
cdb05607e2e073287a81a908564d9d901ccdd687  .git/objects/f7/61ec192d9f0dca3329044b96ebdb12839dbff6

Und der Wert ist anders. Dies liegt beispielsweise daran, dass der Inhalt komprimiert und gespeichert wird.

decompress_sha1.py


import hashlib
import sys
import zlib

if len(sys.argv) != 2:
    print("usage: %s git_object_file" % sys.argv[0])
    sys.exit(-1)

path = sys.argv[1]
try:
    f = open(path)
except Exception:
    print("open %s failed" % path)
    sys.exit(-1)

data = zlib.decompress(f.read())
sha1 = hashlib.sha1(data).hexdigest()
print("%s: %s" % (path, sha1))

Wenn Sie den Hash-Wert nach dem Dekomprimieren mit dem Programm berechnen

% for i in `find .git/objects -type f`; do python ../decompress_sha1.py $i; done
.git/objects/72/943a16fb2c8f38f9dde202b7a70ccc19c52f34: 72943a16fb2c8f38f9dde202b7a70ccc19c52f34
.git/objects/f7/61ec192d9f0dca3329044b96ebdb12839dbff6: f761ec192d9f0dca3329044b96ebdb12839dbff6

Sie können sehen, dass sie richtig übereinstimmen (da die Hash-Werte übereinstimmen, wird erwartet, dass auch der Inhalt übereinstimmt).

Speicherung des Verzeichnisbaums

Ich habe gesehen, wie man den Inhalt einer Datei unter .git / objects / speichert. Git speichert auch Dateinamen und Commit-Protokollnachrichteninformationen in einer Datei unter .git / objects / wird als Git-Objekt bezeichnet.

Zum Zeitpunkt der Erstellung des Repositorys werden keine Objekte gespeichert.

% mkdir repo2
% cd repo2
% git init
Initialized empty Git repository in repo2/.git/
% ls .git
HEAD         config       hooks/       objects/
branches/    description  info/        refs/
% find .git/objects -type f

Fügen wir dem Staging-Bereich mit git add eine Datei hinzu.

% echo aaa > readme.txt
% git add readme.txt
% find .git/objects -type f
.git/objects/72/943a16fb2c8f38f9dde202b7a70ccc19c52f34
% ls .git
HEAD         config       hooks/       info/        refs/
branches/    description  index        objects/

Ein Objekt wurde hinzugefügt und eine Datei namens Index wurde erstellt. Sie können den Inhalt des Git-Objekts mit der Git-Cat-Datei überprüfen.

% git cat-file -t 729
fatal: Not a valid object name 729
% git cat-file -t 7294
blob
% git cat-file -s 7294
4
% wc -c readme.txt
4 readme.txt
% git cat-file -p 7294
aaa
% cat readme.txt
aaa

Als eine Möglichkeit, Cat-File zu verwenden

Als nächstes schreiben wir die im Index enthaltenen Informationen als Objekt aus.

% git write-tree
580c73c39691399d09ad01152ad0a691ce80bccf
% find .git/objects -type f
.git/objects/58/0c73c39691399d09ad01152ad0a691ce80bccf
.git/objects/72/943a16fb2c8f38f9dde202b7a70ccc19c52f34
% git cat-file -t 580c
tree
% git cat-file -p 580c
100644 blob 72943a16fb2c8f38f9dde202b7a70ccc19c52f34    readme.txt

In diesem Moment,

Ich verstehe das.

tree-1.png

Erstellen Sie als Nächstes ein Verzeichnis und eine Datei darunter und versuchen Sie git add.

% mkdir tmp
% echo bbb > tmp/bbb.txt
% git add tmp/bbb.txt
% find .git/objects -type f
.git/objects/58/0c73c39691399d09ad01152ad0a691ce80bccf
.git/objects/72/943a16fb2c8f38f9dde202b7a70ccc19c52f34
.git/objects/f7/61ec192d9f0dca3329044b96ebdb12839dbff6
% git cat-file -t f761
blob
% git cat-file -p f761
bbb

Das neu hinzugefügte Objekt ist ein Blob-Objekt, das den Inhalt von bbb.txt enthält. Wenn Sie in diesem Zustand erneut einen Index als Objekt schreiben

% git write-tree
6434b2415497a42647800c7e828038a2fb6fbbaf
% find .git/objects -type f
.git/objects/58/0c73c39691399d09ad01152ad0a691ce80bccf
.git/objects/5c/40d98927de9cdb27df5b3a7bd4f7ee95dbfc85
.git/objects/64/34b2415497a42647800c7e828038a2fb6fbbaf
.git/objects/72/943a16fb2c8f38f9dde202b7a70ccc19c52f34
.git/objects/f7/61ec192d9f0dca3329044b96ebdb12839dbff6
% git cat-file -t 6434
tree
% git cat-file -p 6434
100644 blob 72943a16fb2c8f38f9dde202b7a70ccc19c52f34    readme.txt
040000 tree 5c40d98927de9cdb27df5b3a7bd4f7ee95dbfc85    tmp
% git cat-file -t 5c40
tree
% git cat-file -p 5c40
100644 blob f761ec192d9f0dca3329044b96ebdb12839dbff6    bbb.txt

Hier,

Sie können sehen, dass.

tree-2.png

Ich habe einen Parser für Baum geschrieben, weil es eine große Sache war.

parse_tree.py


import hashlib
import sys
import zlib

if len(sys.argv) != 2:
    print("usage: %s git_object_file" % sys.argv[0])
    sys.exit(-1)

try:
    f = open(sys.argv[1])
except Exception:
    print("open %s failed" % sys.argv[1])
    sys.exit(-1)

data = zlib.decompress(f.read())
sha1 = hashlib.sha1(data).hexdigest()

eoh = data.find("\0")
if eoh < 0:
    print("no end of header")
    sys.exit(-1)

header = data[:eoh]
t, n = header.split(" ")

if len(data) - eoh - 1 != int(n):
    print("size mismatch %d,%d" % (len(data) - eoh - 1, int(n)))
    sys.exit(-1)
if t != "tree":
    print("not tree: %s" % t)
    sys.exit(-1)

dsize = hashlib.sha1().digest_size
ptr = eoh + 1
while ptr < len(data):
    eorh = data.find("\0", ptr)
    if eorh < 0:
        print("no end of reference header")
        sys.exit(-1)
    mode, name = data[ptr:eorh].split(" ")
    sha1_ = "".join(map(lambda x: "%02x" % ord(x), data[eorh+1:eorh+1+dsize]))
    print("%s (%6s) %s" % (sha1_, mode, name))
    ptr = eorh + 1 + dsize
% python parse_tree.py .git/objects/64/34b2415497a42647800c7e828038a2fb6fbbaf
72943a16fb2c8f38f9dde202b7a70ccc19c52f34 (100644) readme.txt
5c40d98927de9cdb27df5b3a7bd4f7ee95dbfc85 ( 40000) tmp

Die Datenstruktur des Baumobjekts besteht aus zlib-komprimierten Daten (ähnlich wie bei Blob).

Der Inhaltsteil ist

Es ist eine Wiederholung von.

Commit-Verlauf speichern

Nachdem wir zwei Arten von Objekten gesehen haben, Blob und Tree, schauen wir uns am Ende das Commit-Objekt an. Erstellen wir ein Commit, das auf das Baumobjekt "580c" verweist.

% git commit-tree -m "initial commit" 580c
7a5c786478f17fd96b385c725c95d10fa74e4576
% ls .git/objects/7a/5c786478f17fd96b385c725c95d10fa74e4576
.git/objects/7a/5c786478f17fd96b385c725c95d10fa74e4576
% git cat-file -t 7a5c
commit
% git cat-file -p 7a5c
tree 580c73c39691399d09ad01152ad0a691ce80bccf
author Yoichi Nakayama <[email protected]> 1447772602 +0900
committer Yoichi Nakayama <[email protected]> 1447772602 +0900

initial commit

Als nächstes erstellen wir ein Commit, das auf das Baumobjekt "6434" verweist, wobei das Commit-Objekt "7a5c" das übergeordnete Objekt ist.

% git commit-tree -p 7a5c -m "second commit" 6434
88470d975c1875e2e03a46877c13dde9ed2fd1ea
% ls .git/objects/88/470d975c1875e2e03a46877c13dde9ed2fd1ea
.git/objects/88/470d975c1875e2e03a46877c13dde9ed2fd1ea
% git cat-file -t 8847
commit
% git cat-file -p 8847
tree 6434b2415497a42647800c7e828038a2fb6fbbaf
parent 7a5c786478f17fd96b385c725c95d10fa74e4576
author Yoichi Nakayama <[email protected]> 1447772754 +0900
committer Yoichi Nakayama <[email protected]> 1447772754 +0900

second commit

commits.png

Wenn Sie den Hashwert dieses Festschreibungsobjekts in den von HEAD referenzierten Master eingeben, Sie können den Verlauf mit Git-Protokoll anzeigen.

% cat .git/HEAD
ref: refs/heads/master
% echo 88470d975c1875e2e03a46877c13dde9ed2fd1ea > .git/refs/heads/master
% git log
commit 88470d975c1875e2e03a46877c13dde9ed2fd1ea
Author: Yoichi Nakayama <[email protected]>
Date:   Wed Nov 18 00:05:54 2015 +0900

    second commit

commit 7a5c786478f17fd96b385c725c95d10fa74e4576
Author: Yoichi Nakayama <[email protected]>
Date:   Wed Nov 18 00:03:22 2015 +0900

    initial commit

Sie können jetzt den Verlauf anzeigen, den Sie normalerweise nach dem Festschreiben von Git sehen. Sie können git diff auch den Hash-Wert des Ziel-Commit-Objekts geben, um den Unterschied zu sehen.

% git diff 7a5c 8847
diff --git a/tmp/bbb.txt b/tmp/bbb.txt
new file mode 100644
index 0000000..f761ec1
--- /dev/null
+++ b/tmp/bbb.txt
@@ -0,0 +1 @@
+bbb

Die Datenstruktur des Festschreibungsobjekts ist dieselbe wie die des Blob-Objekts, außer dass es mit "Festschreiben" als Inhalt beginnt.

Beinhaltet.

Zusammenfassung

Referenz

Fortsetzung

Recommended Posts

Einführung in Git (1) History-Speicher
Erste Schritte mit Android!
1.1 Erste Schritte mit Python
Erste Schritte mit apache2
Erste Schritte mit Python
Erste Schritte mit Django 1
Einführung in die Optimierung
Erste Schritte mit Numpy
Erste Schritte mit Spark
Erste Schritte mit Python
Erste Schritte mit Pydantic
Erste Schritte mit Jython
Erste Schritte mit Django 2
Übersetzen Erste Schritte mit TensorFlow
Einführung in Tkinter 2: Button
Erste Schritte mit Go Assembly
Erste Schritte mit PKI mit Golang ―― 4
Erste Schritte mit Python Django (1)
Erste Schritte mit Python Django (4)
Erste Schritte mit Python Django (3)
Einführung in Python Django (6)
Erste Schritte mit Django mit PyCharm
Erste Schritte mit Python Django (5)
Erste Schritte mit Python Responder v2
Erste Schritte mit Sphinx. Generieren Sie Docstring mit Sphinx
Erste Schritte mit Python-Webanwendungen
Erste Schritte mit Python für PHPer-Klassen
Erste Schritte mit Sparse Matrix mit scipy.sparse
Erste Schritte mit Julia für Pythonista
Erste Schritte mit Python Grundlagen von Python
Erste Schritte mit der Cisco Spark REST-API
Beginnend mit USD unter Windows
Erste Schritte mit genetischen Python-Algorithmen
Erste Schritte mit Python 3.8 unter Windows
Erste Schritte mit Python für PHPer-Funktionen
Erste Schritte mit der CPU-Diebstahlzeit
Erste Schritte mit Python3 # 1 Grundkenntnisse erlernen
Erste Schritte mit Python Web Scraping Practice
Erste Schritte mit Python für PHPer-Super Basics
Erste Schritte mit Python Web Scraping Practice
Erste Schritte mit Dynamo von Python Boto
Erste Schritte mit Lisp für Pythonista: Ergänzung
Erste Schritte mit Heroku, Bereitstellen der Flaschen-App
Erste Schritte mit TDD mit Cyber-dojo bei MobPro
git mit subprocess.Popen
Grale fangen an
Erste Schritte mit Python mit 100 Klopfen bei der Sprachverarbeitung
Erste Schritte mit dem Zeichnen mit matplotlib: Schreiben einfacher Funktionen
Erste Schritte mit der japanischen Übersetzung des Keras Sequential-Modells
[Übersetzung] Erste Schritte mit Rust für Python-Programmierer
Django Erste Schritte Teil 2 mit dem Eclipse Plugin (PyDev)
Erste Schritte mit AWS IoT in Python
Erste Schritte mit Pythons Ast-Modul (Verwenden von NodeVisitor)
Materialien zum Lesen, wenn Sie mit Python beginnen
Einstellungen für den Einstieg in MongoDB mit Python
Django 1.11 wurde mit Python3.6 gestartet