Μετάβαση στο περιεχόμενο

Δέντρα εργασίας

Τα worktree Git επιτρέπουν σε πολλούς καταλόγους εργασίας να μοιράζονται ένα αποθετήριο. Κάθε worktree έχει το δικό του checkout (HEAD, ευρετήριο, αρχεία εργασίας), αλλά μοιράζεται με το κύριο αποθετήριο το χώρο αποθήκευσης αντικειμένων, τις ρυθμίσεις και τα packed-refs. Το Pitmaster μπορεί να δημιουργεί, να παραθέτει, να κλειδώνει και να αφαιρεί συνδεδεμένα worktree, καθώς και να τα ανοίγει ως αποθετήρια. Η εκκαθάριση, η μετακίνηση και η επιδιόρθωση worktree δεν υλοποιούνται.

Βασικές έννοιες

Ένα κανονικό αποθετήριο git έχει ένα μόνο δέντρο εργασίας:

Κώδικας
project/
  .git/          (directory)
  src/
  README.md

Με τα worktrees, μπορείτε να έχετε επιπλέον checkouts:

Κώδικας
project/                          (main worktree)
  .git/                           (the actual git directory)
    worktrees/
      review/                     (metadata for linked worktree)
        HEAD
        commondir
        gitdir

/tmp/review/                      (linked worktree)
  .git                            (file, not directory)
  src/
  README.md

Το .git του συνδεδεμένου worktree είναι αρχείο (όχι κατάλογος) που περιέχει μια διαδρομή σχετική με το worktree:

Κώδικας
gitdir: ../../path/to/project/.git/worktrees/review

Δημιουργία worktree

PHP
$repo = Pitmaster::open('/path/to/project');

// Create a linked worktree on a new branch
$wt = $repo->addWorktree('/tmp/review', 'feature/review');

echo $wt->path;        // '/tmp/review'
echo $wt->branch;      // 'feature/review'
echo $wt->gitDir;      // '/path/to/project/.git/worktrees/review'
var_dump($wt->isMain);      // bool(false)
var_dump($wt->isDetached);  // bool(false)

addWorktree() εκτελεί τα εξής:

  1. Δημιουργεί τον κλάδο, αν δεν υπάρχει (από το HEAD ή το καθορισμένο commit $from)
  2. Δημιουργεί τον κατάλογο μεταδεδομένων στη θέση .git/worktrees/<name>/
  3. Γράφει το αρχείο .git στον κατάλογο του worktree
  4. Γράφει τα αρχεία μεταδεδομένων HEAD, commondir και gitdir
  5. Κάνει checkout το δέντρο του κλάδου στον κατάλογο του worktree
  6. Γράφει το index για το worktree

Αν ο κλάδος υπάρχει ήδη, το $from αγνοείται. Σε αντίθεση με το git, το addWorktree() δεν αρνείται να χρησιμοποιήσει κλάδο που έχει ήδη γίνει checkout σε άλλο worktree και δεν εκτελεί το hook post-checkout.

Με ρητό όνομα μεταδεδομένων

Χρησιμοποιήστε το προαιρετικό όρισμα name όταν πολλά συνδεδεμένα worktrees μπορούν να έχουν το ίδιο όνομα βάσης checkout.

PHP
$wt = $repo->addWorktree(
    '/tmp/sandboxes/app',
    'feature/review',
    name: 'sandbox-app',
);

Αυτό το όνομα μεταδεδομένων χρησιμοποιείται στη θέση .git/worktrees/<name>/ αντί για basename($path).

Από συγκεκριμένο commit

PHP
$wt = $repo->addWorktree('/tmp/hotfix', 'hotfix/urgent', $repo->resolve('v1.0.0'));

Καταχώριση worktrees

PHP
$worktrees = $repo->worktrees();

foreach ($worktrees as $wt) {
    $type = $wt->isMain ? 'main' : 'linked';
    $branch = $wt->branch ?? 'detached';
    $locked = $wt->isLocked ? ' [locked]' : '';

    echo "{$wt->path} ({$type}) [{$branch}]{$locked}\n";
}

Η λίστα περιλαμβάνει πάντα πρώτο το κύριο worktree και έπειτα τα συνδεδεμένα worktrees. Καλέστε το worktrees() σε ένα handle του κύριου αποθετηρίου: σε ένα handle συνδεδεμένου worktree, η κύρια εγγραφή αναφέρει προς το παρόν τη διαδρομή του ίδιου του συνδεδεμένου worktree (#14).

Αφαίρεση worktree

PHP
$repo->removeWorktree('review');          // by metadata name
$repo->removeWorktree('/tmp/review');     // or by worktree path

// Force remove (even if locked)
$repo->removeWorktree('review', force: true);

Η αφαίρεση ενός worktree:

  1. Ελέγχει αν το worktree είναι κλειδωμένο (αποτυγχάνει εκτός αν το $force είναι true)
  2. Αφαιρεί το αρχείο .git από τον κατάλογο του worktree
  3. Αφαιρεί τον κατάλογο μεταδεδομένων από τη θέση .git/worktrees/

Τα αρχεία του working tree δεν διαγράφονται αυτόματα. Ο κλάδος συνεχίζει να υπάρχει.

Άνοιγμα συνδεδεμένου worktree

Μπορείτε να ανοίξετε ένα συνδεδεμένο worktree όπως οποιοδήποτε αποθετήριο:

PHP
$repo = Pitmaster::open('/tmp/review');

// Pitmaster detects the .git file and follows the gitdir reference
echo $repo->isLinkedWorktree();  // true
echo $repo->gitDir();            // '/path/to/project/.git/worktrees/review'
echo $repo->commonGitDir();      // '/path/to/project/.git'
echo $repo->workDir();           // '/tmp/review'

Οι λειτουργίες του αποθετηρίου επιλύουν τις διαδρομές ως εξής:

  • Αντικείμενα: διαβάζονται από και γράφονται στον κοινό κατάλογο git (project/.git/objects/)
  • Ρυθμίσεις: διαβάζονται από τον κοινό κατάλογο git (project/.git/config)
  • Packed-refs: διαβάζονται από τον κοινό κατάλογο git
  • HEAD: ανά worktree (κάθε worktree παρακολουθεί τον δικό του κλάδο), μαζί με τα ORIG_HEAD, MERGE_HEAD και τις άλλες αναφορές λειτουργιών
  • Index: ανά worktree (κάθε worktree έχει τη δική του περιοχή σταδιοποίησης)
  • Loose refs: οι κλάδοι και οι ετικέτες είναι κοινόχρηστα στον κοινό κατάλογο (project/.git/refs/)
  • Hooks: διαβάζονται από τον κατάλογο git ανά worktree, επομένως τα κοινόχρηστα hooks δεν εκτελούνται (#12)

Το Stash δεν υποστηρίζει ακόμη συνδεδεμένα worktrees: διαβάζει την ταυτότητα από τον κατάλογο ανά worktree, ο οποίος δεν έχει ρυθμίσεις, και γράφει εκεί το reflog του (#14).

Αντικείμενο τιμής Worktree

PHP
use Pitmaster\Worktree\Worktree;

$wt->name;          // Metadata name (null for the main worktree)
$wt->path;          // Working directory path
$wt->gitDir;        // Per-worktree git dir
$wt->branch;        // Branch name (null if detached)
$wt->head;          // ObjectId of HEAD commit
$wt->isMain;        // true for the main worktree
$wt->isDetached;    // true if HEAD is detached
$wt->isLocked;      // true if worktree is locked
$wt->lockReason;    // Lock reason, or null when there is none (an empty reason is also null)

WorktreeManager

Για διαχείριση worktree χαμηλού επιπέδου. Το WorktreeManager::add() γράφει μόνο τα μεταδεδομένα και το αρχείο .git: δεν δημιουργεί τον κλάδο, δεν κάνει checkout αρχεία και δεν γράφει index. Χρησιμοποιήστε το $repo->addWorktree() για ένα λειτουργικό checkout. Ο κλάδος πρέπει να υπάρχει ήδη (ή να είναι πλήρες όνομα ref, όπως το refs/tags/v1.0.0, που αποσυνδέει το HEAD).

PHP
use Pitmaster\Worktree\WorktreeManager;

$manager = new WorktreeManager($repo->commonGitDir(), $mainWorkDir);

// List
$worktrees = $manager->list();

// Add
$wt = $manager->add('/tmp/review', 'feature/review');
$wt = $manager->add('/tmp/review', 'feature/review', 'review-app');

// Remove
$manager->remove('review');
$manager->remove('review', force: true);

// Lock/unlock (metadata name only)
$manager->lock('review', 'Do not delete, code review in progress');
$manager->unlock('review');

Κλείδωμα worktrees

PHP
// Lock (prevents removal)
$manager->lock('review', 'Code review in progress');

// Attempt to remove locked worktree
try {
    $manager->remove('review');
} catch (\RuntimeException $e) {
    // "Worktree is locked: review (Code review in progress)"
}

// Force remove ignores the lock
$manager->remove('review', force: true);

// Unlock
$manager->unlock('review');

Το κλείδωμα αποθηκεύεται ως αρχείο στη θέση .git/worktrees/<name>/locked. Το περιεχόμενο του αρχείου είναι ο λόγος κλειδώματος (μπορεί να είναι κενό).

Εντοπισμός worktrees

PHP
// Check if a path is a linked worktree
if (Pitmaster::isWorktree('/tmp/review')) {
    echo "This is a linked worktree\n";
}

// Resolve the common git dir from any path
$common = Pitmaster::commonGitDir('/tmp/review');
// '/path/to/project/.git'

// Resolve a .git file to the actual git directory
$gitDir = WorktreeManager::resolveGitFile('/tmp/review');
// '/path/to/project/.git/worktrees/review'

Διάταξη αρχείων

Μεταδεδομένα κύριου worktree για συνδεδεμένα worktrees

Κώδικας
.git/worktrees/<name>/
  HEAD         Per-worktree HEAD (symbolic ref or detached hash)
  commondir    Relative path to the shared git dir ("../..")
  gitdir       Path back to the worktree's .git file, as passed to addWorktree()
  locked       Present if locked (content = reason)
  index        Per-worktree index/staging area

Αρχείο .git συνδεδεμένου worktree

Κώδικας
gitdir: <relative path to>/project/.git/worktrees/<name>

Κοινή χρήση πόρων

Πόρος Τοποθεσία Κοινόχρηστος;
Αντικείμενα $commonDir/objects/ Ναι
Ρυθμίσεις $commonDir/config Ναι
Packed-refs $commonDir/packed-refs Ναι
Hooks $gitDir/hooks/ Όχι: το Pitmaster δεν εκτελεί τα κοινόχρηστα hooks σε συνδεδεμένα worktrees
HEAD $gitDir/HEAD Όχι (ανά worktree)
Index $gitDir/index Όχι (ανά worktree)
Loose refs $commonDir/refs/ Ναι (το HEAD και οι αναφορές λειτουργιών, όπως το MERGE_HEAD, είναι ανά worktree)