Perforce ist ein sehr beliebtes Versionskontrollsystem in Unternehmen. Es existiert seit 1995 und ist damit das älteste in diesem Kapitel behandelte System. Altersbedingt hat das Konzept aus heutiger Sicht einige Einschränkungen. Es geht davon aus, dass du immer mit einem einzigen zentralen Server verbunden bist und nur eine Version auf der lokalen Festplatte gespeichert ist. Sicherlich sind seine Funktionen und Einschränkungen gut für einige spezielle Probleme geeignet, aber es gibt viele Projekte mit Perforce, bei denen Git möglicherweise besser geeignet wäre.
Es gibt zwei Möglichkeiten, wenn du Perforce und Git zusammen nutzen möchtest. Als erstes stellen wir die „Git Fusion“ Bridge des Herstellers von Perforce vor, mit der du Teilbäume deines Perforce-Depots als Read-Write-Git-Repository freigeben kannst. Bei der zweiten handelt es sich um git-p4, eine client-seitige Bridge, mit der du Git als Perforce-Client verwenden kannst, ohne dass der Perforce-Server neu konfiguriert werden muss.
Preforce bietet mit Git Fusion ein Produkt (verfügbar unter https://www.perforce.com/git-fusion), das einen Perforce-Server mit Git-Repositorys auf der Serverseite synchronisiert.
Für unsere Beispiele verwenden wir die einfachste Installationsmethode für Git Fusion, indem wir eine virtuelle Maschine herunterladen, auf der der Perforce-Daemon und Git Fusion laufen. Du kannst das Image der virtuellen Maschine von https://www.perforce.com/downloads/Perforce/20-User herunterladen. Wenn der Download abgeschlossen ist, importierst du es in deiner bevorzugten Virtualisierungssoftware (wir verwenden VirtualBox).
Beim ersten Start des Rechners wirst du aufgefordert, das Passwort für drei Linux-Benutzer (root
, perforce
, git
) festzulegen und einen Instanznamen anzugeben, mit dem du diese Installation von anderen im selben Netzwerk unterscheiden kannst.
Wenn das alles abgeschlossen ist, solltest du folgendes sehen:
Du solltest die hier angezeigte IP-Adresse notieren, wir werden sie später benutzen.
Als nächstes erstellen wir einen Perforce-Benutzer.
Wähle unten die Option „Login“ und drücke die Eingabetaste (oder verbinde dich per SSH mit dem Computer) und melde dich als root
an.
Verwende anschliessend folgenden Befehle, um einen Benutzer anzulegen:
$ p4 -p localhost:1666 -u super user -f john
$ p4 -p localhost:1666 -u john passwd
$ exit
Der erste öffnet einen VI-Editor, um den Benutzer zu personalisieren. Du kannst auch die Vorgaben übernehmen, indem du :wq
eingibst und auf Enter drückst.
Der zweite wird dich auffordern, ein Passwort zweimal einzugeben.
Das ist alles, was wir mit einem Shell-Prompt zu tun haben werden, also beende die Sitzung.
Als nächstes musst du Git mitteilen, dass es keine SSL-Zertifikate überprüfen soll. Das Git Fusion-Image wird mit einem Zertifikat geliefert, aber es bezieht sich auf eine Domäne, die nicht mit der IP-Adresse deiner virtuellen Maschine übereinstimmt, weshalb Git die HTTPS-Verbindung abweisen würde. Wenn dies eine permanente Installation sein soll, lies das Handbuch von Perforce Git Fusion, um ein anderes Zertifikat zu installieren. Für unsere Beispielzwecke genügt diese Angabe:
$ export GIT_SSL_NO_VERIFY=true
Jetzt können wir testen, ob alles funktioniert.
$ git clone https://10.0.1.254/Talkhouse
Cloning into 'Talkhouse'...
Username for 'https://10.0.1.254': john
Password for 'https://[email protected]':
remote: Counting objects: 630, done.
remote: Compressing objects: 100% (581/581), done.
remote: Total 630 (delta 172), reused 0 (delta 0)
Receiving objects: 100% (630/630), 1.22 MiB | 0 bytes/s, done.
Resolving deltas: 100% (172/172), done.
Checking connectivity... done.
Das Virtual-Machine-Image ist mit einem Beispielprojekt ausgestattet, das du klonen kannst.
Hier klonen wir über HTTPS, mit dem Benutzer john
, den wir oben erstellt haben. Git fragt nach Anmeldeinformationen für diese Verbindung, aber der Credential-Cache erlaubt es uns, diesen Schritt für alle nachfolgenden Anfragen zu überspringen.
Sobald du Git Fusion installiert hast, solltest du die Konfiguration anpassen.
Mit deinem favorisierten Perforce-Client ist das ganz einfach. Weise das Verzeichnis //.git-fusion
auf dem Perforce-Server einfach deinem Arbeitsbereich zu.
Die Dateistruktur sieht wie folgt aus:
$ tree
.
├── objects
│ ├── repos
│ │ └── [...]
│ └── trees
│ └── [...]
│
├── p4gf_config
├── repos
│ └── Talkhouse
│ └── p4gf_config
└── users
└── p4gf_usermap
498 directories, 287 files
Das Verzeichnis objects
wird intern von Git Fusion verwendet, um Perforce-Objekte auf Git abzubilden und umgekehrt, so dass du es ignorieren kannst.
In diesem Verzeichnis gibt es eine globale p4gf_config
Datei sowie eine für jedes Repository – das sind die Konfigurationsdateien, die das Verhalten von Git Fusion bestimmen.
Werfen wir einen Blick auf die Datei im Root:
[repo-creation]
charset = utf8
[git-to-perforce]
change-owner = author
enable-git-branch-creation = yes
enable-swarm-reviews = yes
enable-git-merge-commits = yes
enable-git-submodules = yes
preflight-commit = none
ignore-author-permissions = no
read-permission-check = none
git-merge-avoidance-after-change-num = 12107
[perforce-to-git]
http-url = none
ssh-url = none
[@features]
imports = False
chunked-push = False
matrix2 = False
parallel-push = False
[authentication]
email-case-sensitivity = no
Wir werden hier nicht auf die Bedeutung all dieser Flags eingehen. Bedenke jedoch, dass es sich hierbei nur um eine INI-formatierte Textdatei handelt, ähnlich wie bei der Konfiguration mit Git.
Diese Datei legt die globalen Optionen fest, die dann von repository-spezifischen Konfigurationsdateien wie repos/Talkhouse/p4gf_config
überschrieben werden können.
Wenn du diese Datei öffnest, siehst du einen Abschnitt [@repo]
mit einigen Einstellungen, die sich von den globalen Standardeinstellungen unterscheiden.
Du wirst auch Abschnitte sehen, die so aussehen:
[Talkhouse-master]
git-branch-name = master
view = //depot/Talkhouse/main-dev/... ...
Dabei handelt es sich um eine Zuordnung zwischen einem Perforce-Branch und einem Git-Branch.
Der Abschnitt kann beliebig benannt werden, solange der Name eindeutig ist.
Der git-branch-name
ermöglicht dir, einen Depot-Pfad, der unter Git umständlich wäre, in einen benutzerfreundlicheren Namen zu konvertieren.
Die Anzeige-Einstellung steuert, wie Perforce-Dateien in das Git-Repository mit Hilfe der Standard-Syntax für das View-Mapping abgebildet werden.
Es kann mehr als ein Mapping angegeben werden, wie in diesem Beispiel:
[multi-project-mapping]
git-branch-name = master
view = //depot/project1/main/... project1/...
//depot/project2/mainline/... project2/...
Wenn dein normales Workspace-Mapping Änderungen in der Struktur der Verzeichnisse enthält, kannst du das auf diese Weise mit einem Git-Repository replizieren.
Die letzte Datei, die wir hier behandeln, ist users/p4gf_usermap
, die Perforce-Benutzer auf Git-Benutzer abbildet und die du möglicherweise nicht einmal benötigst.
Bei der Konvertierung eines Perforce Change-Sets in einen Git Commit sucht Git Fusion standardmäßig nach dem Perforce-Benutzer und verwendet die dort gespeicherte E-Mail-Adresse und den vollständigen Namen für das Autor/Committer-Feld in Git.
Bei der umgekehrten Konvertierung wird standardmäßig der Perforce-Benutzer mit der E-Mail-Adresse gesucht, die im Autorenfeld des Git-Commits gespeichert ist, und das Änderungsset als dieser Benutzer übermittelt (mit entsprechenden Berechtigungen).
In den meisten Fällen wird dieses Verhalten gut funktionieren, aber beachte die folgende Mapping-Datei:
john [email protected] "John Doe"
john [email protected] "John Doe"
bob [email protected] "Anon X. Mouse"
joe [email protected] "Anon Y. Mouse"
Jede Zeile hat das Format <user> <email> "<full name>"
und erstellt eine einzige Benutzerzuordnung.
Die beiden ersten Zeilen ordnen zwei verschiedene E-Mail-Adressen demselben Perforce-Benutzerkonto zu.
Das ist praktisch, wenn du Git-Commits unter mehreren verschiedenen E-Mail-Adressen erstellt hast (oder sich deine E-Mail-Adresse ändert), diese aber dem gleichen Perforce-Benutzer zugeordnet werden sollen.
Beim Erstellen eines Git-Commits aus einem Perforce Change-Set wird die erste Zeile, die dem Perforce-Benutzer entspricht, für die Angaben zur Git-Autorschaft verwendet.
Die letzten beiden Zeilen überdecken Bob und Joe’s tatsächliche Namen und E-Mail-Adressen aus den Git-Commits, die erstellt werden. Das ist sinnvoll, wenn du ein internes Projekt open-source-fähig machen willst, aber dein Mitarbeiterverzeichnis nicht auf der ganzen Welt veröffentlichen willst. Beachte, dass die E-Mail-Adressen und vollständigen Namen eindeutig sein sollten, es sei denn, du möchtest alle Git-Commits einem einzigen fiktiven Autor zuordnen.
Perforce Git Fusion ist eine bidirektionale Brücke zwischen der Perforce- und Git-Versionskontrolle. Betrachten wir die Arbeit von der Git-Seite aus. Wir gehen davon aus, dass wir im Projekt „Jam“ mit einer oben gezeigten Konfigurationsdatei gemapped sind, die wir so klonen können:
$ git clone https://10.0.1.254/Jam
Cloning into 'Jam'...
Username for 'https://10.0.1.254': john
Password for 'https://[email protected]':
remote: Counting objects: 2070, done.
remote: Compressing objects: 100% (1704/1704), done.
Receiving objects: 100% (2070/2070), 1.21 MiB | 0 bytes/s, done.
remote: Total 2070 (delta 1242), reused 0 (delta 0)
Resolving deltas: 100% (1242/1242), done.
Checking connectivity... done.
$ git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/master
remotes/origin/rel2.1
$ git log --oneline --decorate --graph --all
* 0a38c33 (origin/rel2.1) Create Jam 2.1 release branch.
| * d254865 (HEAD, origin/master, origin/HEAD, master) Upgrade to latest metrowerks on Beos -- the Intel one.
| * bd2f54a Put in fix for jam's NT handle leak.
| * c0f29e7 Fix URL in a jam doc
| * cc644ac Radstone's lynx port.
[...]
Wenn du das zum ersten Mal machst, kann es einige Zeit in Anspruch nehmen. Git Fusion konvertiert alle anwendbaren Changesets in der Perforce-Historie in Git-Commits. Das passiert lokal auf dem Server, ist also relativ schnell, aber wenn man einen langen Verlauf hat, kann es trotzdem einige Zeit dauern. Nachfolgende Fetches führen eine inkrementelle Konvertierung durch, so dass es sich schon eher wie die native Geschwindigkeit von Git anfühlt.
Wie du siehst, sieht unser Repository genauso aus wie jedes andere Git-Repository, mit dem du arbeiten kannst.
Es gibt drei Branches. Git hat einen lokalen master
Branch erstellt, der origin/master
tracked.
Wir werden ein wenig arbeiten und ein paar neue Commits erstellen:
# ...
$ git log --oneline --decorate --graph --all
* cfd46ab (HEAD, master) Add documentation for new feature
* a730d77 Whitespace
* d254865 (origin/master, origin/HEAD) Upgrade to latest metrowerks on Beos -- the Intel one.
* bd2f54a Put in fix for jam's NT handle leak.
[...]
Wir haben zwei neue Commits. Nun lass uns überprüfen, ob jemand anderes auch daran gearbeitet hat:
$ git fetch
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://10.0.1.254/Jam
d254865..6afeb15 master -> origin/master
$ git log --oneline --decorate --graph --all
* 6afeb15 (origin/master, origin/HEAD) Update copyright
| * cfd46ab (HEAD, master) Add documentation for new feature
| * a730d77 Whitespace
|/
* d254865 Upgrade to latest metrowerks on Beos -- the Intel one.
* bd2f54a Put in fix for jam's NT handle leak.
[...]
Anscheinend hat jemand das tatsächlich getan!
Du würdest es aus dieser Sicht nicht erkennen, aber der 6afeb15
Commit wurde mit einem Perforce Client erstellt.
Es sieht aus der Perspektive von Git wie ein weiterer Commit aus. Das ist genau der Punkt.
Betrachten wir, wie der Perforce-Server mit einem Merge-Commit umgeht:
$ git merge origin/master
Auto-merging README
Merge made by the 'recursive' strategy.
README | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
$ git push
Counting objects: 9, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (9/9), 917 bytes | 0 bytes/s, done.
Total 9 (delta 6), reused 0 (delta 0)
remote: Perforce: 100% (3/3) Loading commit tree into memory...
remote: Perforce: 100% (5/5) Finding child commits...
remote: Perforce: Running git fast-export...
remote: Perforce: 100% (3/3) Checking commits...
remote: Processing will continue even if connection is closed.
remote: Perforce: 100% (3/3) Copying changelists...
remote: Perforce: Submitting new Git commit objects to Perforce: 4
To https://10.0.1.254/Jam
6afeb15..89cba2b master -> master
Git glaubt, dass es funktioniert hat.
Werfen wir einen Blick auf den Verlauf der README
Datei aus der Perspektive von Perforce, indem wir die Revisionsgraphenfunktion von p4v
verwenden:
Wenn du diese Darstellung noch nie zuvor gesehen hast, mag sie verwirrend erscheinen, aber sie zeigt die gleichen Konzepte wie ein grafischer Viewer für die Git-Historie.
Wir betrachten die Historie der README
Datei, so dass der Verzeichnisbaum oben links nur diese Datei anzeigt, wenn sie in verschiedenen Branches auftaucht.
Oben rechts haben wir ein Diagramm, das veranschaulicht, wie verschiedene Revisionen der Datei zusammenhängen, und die vergrößerte Ansicht dieses Diagramms befindet sich unten rechts.
Der Rest der Darstellung wird der Detailansicht für die ausgewählte Revision (in diesem Fall 2
) übergeben.
Auffällig ist, dass die Grafik genau so aussieht wie die in dem Verlauf von Git.
Perforce hatte keinen namentlich benannten Branch, um die Commits 1
und 2
zu speichern. Also wurde ein „anonymer“ Branch im .git-fusion
Verzeichnis erstellt, um sie zu speichern.
Das gilt auch für benannte Git-Branches, die keinem benannten Perforce-Branch entsprechen (Du kannst sie später über die Konfigurationsdatei einem Perforce-Branch zuordnen).
Das meiste geschieht hinter den Kulissen, und das Ergebnis ist, dass eine Person in der Gruppe Git und eine andere Perforce verwenden kann wobei keine von ihnen von der Entscheidung der anderen Person weiß.
Wenn du Zugang zu deinem Perforce-Server hadt (oder erhalten kannst), ist Git Fusion eine gute Möglichkeit, Git und Perforce zum gegenseitigen Austausch zu bewegen. Es ist ein wenig Konfiguration erforderlich, aber die Lernkurve ist nicht sehr steil. Dieses ist einer der wenigen Abschnitte in diesem Kapitel, in denen Warnungen über die Verwendung von Gits voller Leistung nicht erscheinen. Das heißt nicht, dass Perforce mit allem, was du ihm zumutest, zufrieden sein wirst – wenn du versuchst, eine bereits gepushte Historie neu zu schreiben, wird Git Fusion sie ablehnen – aber Git Fusion gibt sich sehr große Mühe, sich nativ anzufühlen. Du kannst sogar Git-Submodule verwenden (obwohl sie für Perforce-Anwender seltsam aussehen werden) und Branches mergen (das wird als Integration auf der Perforce-Seite erfasst).
Wenn du den Administrator deines Servers nicht davon überzeugen kannst, Git Fusion einzurichten, gibt es noch eine weitere Möglichkeit, diese Tools gemeinsam zu nutzen.
Git-p4 ist eine bidirektionale Brücke zwischen Git und Perforce. Es läuft vollständig in deinem Git-Repository, so dass du keinen Zugriff auf den Perforce-Server benötigst (mit Ausnahme der Benutzer-Anmeldeinformationen). Git-p4 ist nicht so flexibel und keine Komplettlösung wie Git Fusion, aber es ermöglicht dir, das meiste von dem zu tun, was du tun möchtest, ohne die Serverumgebung zu beeinträchtigen.
Note
|
Du brauchst das |
So werden wir beispielsweise den Perforce-Server wie oben gezeigt von der Git Fusion OVA (Open-Virtualization-Archive-Datei) aus verwenden, aber wir umgehen den Git Fusion-Server und gehen direkt zur Perforce-Versionskontrolle.
Um den von git-p4 benötigten Befehlszeilen-Client p4
verwenden zu können, musst du ein paar Umgebungsvariablen setzen:
$ export P4PORT=10.0.1.254:1666
$ export P4USER=john
Wie bei allem in Git ist das Klonen der erste Befehl:
$ git p4 clone //depot/www/live www-shallow
Importing from //depot/www/live into www-shallow
Initialized empty Git repository in /private/tmp/www-shallow/.git/
Doing initial import of //depot/www/live/ from revision #head into refs/remotes/p4/master
Dadurch entsteht ein Git-technisch „flacher“ Klon. Nur die allerletzte Perforce-Revision wird in Git importiert. Denke daran, Perforce ist nicht dazu gedacht, jedem Benutzer alle Revisionen zu übergeben. Das ist ausreichend, um Git als Perforce-Client zu verwenden, ist aber für andere Zwecke ungeeignet.
Sobald es abgeschlossen ist, haben wir ein voll funktionsfähiges Git-Repository:
$ cd myproject
$ git log --oneline --all --graph --decorate
* 70eaf78 (HEAD, p4/master, p4/HEAD, master) Initial import of //depot/www/live/ from the state at revision #head
Beachte, dass es für den Perforce-Server einen „p4“ Remote gibt, aber alles andere sieht aus wie ein Standardklon. Eigentlich ist das etwas irreführend; es gibt dort nicht wirklich einen Remote.
$ git remote -v
In diesem Repository existieren überhaupt keine Remotes.
Git-p4 hat einige Referenzen erstellt, um den Zustand des Servers darzustellen. Für git log
sehen sie aus wie Remote-Referenzen, aber sie werden nicht von Git selbst verwaltet. Man kann nicht zu ihnen pushen.
Okay, lass uns ein paar Arbeiten erledigen. Nehmen wir an, du hast einige Änderungen bei einem sehr wichtigen Feature gemacht und bist bereit, es dem Rest deines Teams zu zeigen.
$ git log --oneline --all --graph --decorate
* 018467c (HEAD, master) Change page title
* c0fb617 Update link
* 70eaf78 (p4/master, p4/HEAD) Initial import of //depot/www/live/ from the state at revision #head
Wir haben zwei neue Commits erstellt, die wir an den Perforce-Server übermitteln können. Schauen wir mal, ob heute noch jemand anderes Änderungen gemacht hat:
$ git p4 sync
git p4 sync
Performing incremental import into refs/remotes/p4/master git branch
Depot paths: //depot/www/live/
Import destination: refs/remotes/p4/master
Importing revision 12142 (100%)
$ git log --oneline --all --graph --decorate
* 75cd059 (p4/master, p4/HEAD) Update copyright
| * 018467c (HEAD, master) Change page title
| * c0fb617 Update link
|/
* 70eaf78 Initial import of //depot/www/live/ from the state at revision #head
Tatsächlich wurde etwas geändert. Die Branches master
und p4/master
sind auseinander gelaufen.
Das Branching-System von Perforce ist nicht wie das von Git, so dass das Übertragen von Merge-Commits keinen Sinn macht.
Git-p4 empfiehlt, dass du deine Commits rebased und bietet sogar eine Kurzform dafür:
$ git p4 rebase
Performing incremental import into refs/remotes/p4/master git branch
Depot paths: //depot/www/live/
No changes to import!
Rebasing the current branch onto remotes/p4/master
First, rewinding head to replay your work on top of it...
Applying: Update link
Applying: Change page title
index.html | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Vermutlich kannst du das an der Ausgabe erkennen: git p4 rebase
ist eine Abkürzung für git p4 sync
gefolgt von git rebase p4/master
.
Das ist zwar noch ein bisschen cleverer, besonders bei der Arbeit mit mehreren Branches, ist aber eine gute Annäherung.
Jetzt ist unser Verlauf wieder linear und bereit, in Perforce eingereicht zu werden.
Der Befehl git p4 submit
versucht, für jeden Git-Commit zwischen p4/master
und master
, eine neue Perforce-Revision zu erstellen.
Beim Ausführen werden wir in unseren bevorzugten Editor weitergeleitet, der Inhalt der Datei sieht dann ungefähr so aus:
# A Perforce Change Specification.
#
# Change: The change number. 'new' on a new changelist.
# Date: The date this specification was last modified.
# Client: The client on which the changelist was created. Read-only.
# User: The user who created the changelist.
# Status: Either 'pending' or 'submitted'. Read-only.
# Type: Either 'public' or 'restricted'. Default is 'public'.
# Description: Comments about the changelist. Required.
# Jobs: What opened jobs are to be closed by this changelist.
# You may delete jobs from this list. (New changelists only.)
# Files: What opened files from the default changelist are to be added
# to this changelist. You may delete files from this list.
# (New changelists only.)
Change: new
Client: john_bens-mbp_8487
User: john
Status: new
Description:
Update link
Files:
//depot/www/live/index.html # edit
######## git author [email protected] does not match your p4 account.
######## Use option --preserve-user to modify authorship.
######## Variable git-p4.skipUserNameCheck hides this message.
######## everything below this line is just the diff #######
--- //depot/www/live/index.html 2014-08-31 18:26:05.000000000 0000
+++ /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/index.html 2014-08-31 18:26:05.000000000 0000
@@ -60,7 +60,7 @@
</td>
<td valign=top>
Source and documentation for
-<a href="http://www.perforce.com/jam/jam.html">
+<a href="jam.html">
Jam/MR</a>,
a software build tool.
</td>
Das ist im Wesentlichen derselbe Inhalt, den du bei der Ausführung von p4 submit
sehen würdest. Ausgenommen sind die Dinge am Ende, die git-p4 sinnvollerweise mit aufgenommen hat.
Git-p4 versucht, deine Git- und Perforce-Einstellungen individuell zu berücksichtigen, wenn es einen Namen für ein Commit- oder Changeset angeben muss. In einigen Fällen willst du ihn eventuell überschreiben.
Wenn beispielsweise der Git-Commit, den du importierst, von einem Mitwirkenden geschrieben wurde, der kein Perforce-Benutzerkonto hat, kannst du trotzdem wollen, dass sich das daraus ergebende Changeset so aussieht, als hätte er es geschrieben (und nicht du).
Git-p4 hat die Nachricht aus dem Git-Commit zweckmäßigerweise als Inhalt für dieses Perforce Changeset importiert. Alles, was wir tun müssen, ist zweimal speichern (einmal für jeden Commit) und beenden. Die resultierende Shell-Ausgabe sieht in etwa so aus:
$ git p4 submit
Perforce checkout for depot path //depot/www/live/ located at /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/
Synchronizing p4 checkout...
... - file(s) up-to-date.
Applying dbac45b Update link
//depot/www/live/index.html#4 - opened for edit
Change 12143 created with 1 open file(s).
Submitting change 12143.
Locking 1 files ...
edit //depot/www/live/index.html#5
Change 12143 submitted.
Applying 905ec6a Change page title
//depot/www/live/index.html#5 - opened for edit
Change 12144 created with 1 open file(s).
Submitting change 12144.
Locking 1 files ...
edit //depot/www/live/index.html#6
Change 12144 submitted.
All commits applied!
Performing incremental import into refs/remotes/p4/master git branch
Depot paths: //depot/www/live/
Import destination: refs/remotes/p4/master
Importing revision 12144 (100%)
Rebasing the current branch onto remotes/p4/master
First, rewinding head to replay your work on top of it...
$ git log --oneline --all --graph --decorate
* 775a46f (HEAD, p4/master, p4/HEAD, master) Change page title
* 05f1ade Update link
* 75cd059 Update copyright
* 70eaf78 Initial import of //depot/www/live/ from the state at revision #head
Das Ergebnis sieht so aus, als ob wir gerade ein git push
gemacht hätten. Das kommt dem, was tatsächlich passiert sehr nahe.
Beachte, dass während dieses Prozesses jeder Git-Commit in einen Perforce Changeset umgewandelt wird. Wenn du ihn in einen einzelnen Changeset zusammenfassen möchtest, kannst du dies mit einem interaktiven Rebase tun, bevor du git p4 submit
ausführst.
Bitte bedenke, dass die SHA-1-Hashes aller Commits, die als Changesets eingereicht wurden, sich geändert haben. Der Grund dafür ist, dass git-p4 am Ende jedes Commits, den es konvertiert, eine Zeile hinzufügt:
$ git log -1
commit 775a46f630d8b46535fc9983cf3ebe6b9aa53145
Author: John Doe <[email protected]>
Date: Sun Aug 31 10:31:44 2014 -0800
Change page title
[git-p4: depot-paths = "//depot/www/live/": change = 12144]
Was passiert, wenn du versuchst, einen Merge-Commit einzureichen? Versuchen wir es einmal. Dies ist der Zustand, in die wir jetzt sind:
$ git log --oneline --all --graph --decorate
* 3be6fd8 (HEAD, master) Correct email address
* 1dcbf21 Merge remote-tracking branch 'p4/master'
|\
| * c4689fc (p4/master, p4/HEAD) Grammar fix
* | cbacd0a Table borders: yes please
* | b4959b6 Trademark
|/
* 775a46f Change page title
* 05f1ade Update link
* 75cd059 Update copyright
* 70eaf78 Initial import of //depot/www/live/ from the state at revision #head
Der Verlauf von Git und Perforce weicht nach 775a46f voneinander ab. Die Git-Seite hat zwei Commits, dann einen Merge-Commit mit dem Perforce Head, dann einen weiteren Commit. Wir werden versuchen, diese auf einem einzelnen Changeset auf der Perforce-Seite einzureichen. Schauen wir mal was passiert, wenn wir versuchen, ihn jetzt einzubringen:
$ git p4 submit -n
Perforce checkout for depot path //depot/www/live/ located at /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/
Would synchronize p4 checkout in /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/
Would apply
b4959b6 Trademark
cbacd0a Table borders: yes please
3be6fd8 Correct email address
Das -n
Flag ist die Abkürzung für --dry-run
. Das bedeutet der Befehlt wir nur simuliert und nicht wirklich ausgeführt. Es erfolgt jedoch eine Ausgabe, was passieren würde, würde man ihn wirklich ausführen, was sehr hilfreich ist.
Hier sieht es so aus, als hätten wir drei Perforce-Änderungssets erstellt, die den drei Nicht-Merge-Commits entsprechen, die noch nicht auf dem Perforce-Server vorhanden sind.
Das hört sich nach genau dem an, was wir wollen. Lass es uns jetzt wirklich ausführen und sehen was passiert:
$ git p4 submit
[…]
$ git log --oneline --all --graph --decorate
* dadbd89 (HEAD, p4/master, p4/HEAD, master) Correct email address
* 1b79a80 Table borders: yes please
* 0097235 Trademark
* c4689fc Grammar fix
* 775a46f Change page title
* 05f1ade Update link
* 75cd059 Update copyright
* 70eaf78 Initial import of //depot/www/live/ from the state at revision #head
Unsere Historie wurde linearisiert, genau so, als hätten wir vor dem Einreichen rebased, was auch tatsächlich passiert ist. So kannst du auf der Git-Seite selbst Branches erstellen, darauf arbeiten, verwerfen und mergen, ohne befürchten zu müssen, dass dein Verlauf sich mit Perforce nicht mehr verträgt. Wenn du einen Rebase durchführen kannst, ist es auch möglich, ihn zu einem Perforce-Server beizusteuern.
Wenn dein Perforce-Projekt mehrere Branches hat, hast du Glück gehabt. git-p4 kann damit so umgehen, dass es sich wie Git anfühlt. Angenommen, dein Perforce-Depot ist so aufgebaut:
//depot
└── project
├── main
└── dev
Nehmen wir weiter an, du hast einen dev
Branch, der eine View-Spezifikation hat, die so aussieht:
//depot/project/main/... //depot/project/dev/...
Git-p4 kann diese Situation automatisch erkennen und das Richtige tun:
$ git p4 clone --detect-branches //depot/project@all
Importing from //depot/project@all into project
Initialized empty Git repository in /private/tmp/project/.git/
Importing revision 20 (50%)
Importing new branch project/dev
Resuming with change 20
Importing revision 22 (100%)
Updated branches: main dev
$ cd project; git log --oneline --all --graph --decorate
* eae77ae (HEAD, p4/master, p4/HEAD, master) main
| * 10d55fb (p4/project/dev) dev
| * a43cfae Populate //depot/project/main/... //depot/project/dev/....
|/
* 2b83451 Project init
Beachte den „@all“ Spezifikator im Depotpfad, der git-p4 anweist, nicht nur das neueste Changeset für diesen Teilbaum, sondern alle Changesets, die jemals diese Pfade beeinflusst haben, zu klonen. Das ist näher an Gits Konzept des Klonens, aber wenn du an einem Projekt mit einer langen Historie arbeitest, könnte es einige Zeit dauern den Klon zu kopieren.
Das --detect-branches
Flag weist git-p4 an, die Branch-Spezifikationen von Perforce zu verwenden, um die Branches den Git refs zuzuordnen.
Sind diese Zuordnungen nicht auf dem Perforce-Server vorhanden (was eine absolut zulässige Methode zur Verwendung von Perforce ist), kannst du git-p4 mitteilen, wie die Zuordnung der Branches zu sein hat. Du erhältst dann das gleiche Ergebnis:
$ git init project
Initialized empty Git repository in /tmp/project/.git/
$ cd project
$ git config git-p4.branchList main:dev
$ git clone --detect-branches //depot/project@all .
Das Setzen der Konfigurationsvariablen git-p4.branchList
auf main:dev
teilt git-p4 mit, dass „main“ und „dev“ beides Branches sind, wobei der zweite ein untergeordnetes Element des ersten ist.
Machen wir jetzt neben git checkout -b dev p4/project/dev
noch einige Commits, dann ist git-p4 klug genug, um den richtigen Branch anzusprechen, wenn wir anschließend git p4 submit
ausführen.
Leider kann git-p4 keine flachen Klone mit mehreren Branches mischen. Wenn du ein großes Projekt hast und an mehr als einem Branch arbeiten willst, musst du jeden Branch, den du einreichen möchtest, einmal mit git p4 clone
erstellen.
Für die Erstellung oder Integration von Branches musst du einen Perforce-Client verwenden. Git-p4 kann nur synchronisieren und an bestehende Branches senden und es kann nur einen linearen Changeset auf einmal durchführen. Bei dem Mergen zweier Branches in Git und dem Versuch, das neue Changeset einzureichen, wird nur ein Bündel von Dateiänderungen aufgezeichnet. Die Metadaten über die an der Integration beteiligten Branches gehen dabei verloren.
Git-p4 ermöglicht die Verwendung eines Git-Workflows mit einem Perforce-Server und ist darin ziemlich gut. Es ist jedoch wichtig, sich klar zu machen, dass Perforce für den Quellcode verantwortlich ist und du Git nur für die lokale Arbeit verwendest. Sei einfach sehr vorsichtig bei der Weitergabe von Git-Commits. Wenn du einen Remote hast, den auch andere Benutzer verwenden, pushe keine Commits, die zuvor noch nicht an den Perforce-Server übertragen wurden.
Möchtest du die Verwendung von Perforce und Git als Clients für die Versionskontrolle frei kombinieren, dann musst du den Server-Administrator davon überzeugen, Git zu installieren. Git Fusion macht die Verwendung von Git zu einem erstklassigen Versionskontroll-Client für einen Perforce-Server.