aboutsummaryrefslogtreecommitdiffstats
path: root/library/kzykhys/git/src/PHPGit/Command/StatusCommand.php
blob: c2bc983fef0ac02d8da4670f3591159bd318f142 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
<?php

namespace PHPGit\Command;

use PHPGit\Command;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

/**
 * Show the working tree status - `git status`
 *
 *   = unmodified
 * M = modified
 * A = added
 * D = deleted
 * R = renamed
 * C = copied
 * U = updated but unmerged
 *
 * X          Y     Meaning
 * -------------------------------------------------
 * [MD]   not updated
 * M        [ MD]   updated in index
 * A        [ MD]   added to index
 * D         [ M]   deleted from index
 * R        [ MD]   renamed in index
 * C        [ MD]   copied in index
 * [MARC]           index and work tree matches
 * [ MARC]     M    work tree changed since index
 * [ MARC]     D    deleted in work tree
 * -------------------------------------------------
 * D           D    unmerged, both deleted
 * A           U    unmerged, added by us
 * U           D    unmerged, deleted by them
 * U           A    unmerged, added by them
 * D           U    unmerged, deleted by us
 * A           A    unmerged, both added
 * U           U    unmerged, both modified
 * -------------------------------------------------
 * ?           ?    untracked
 * !           !    ignored
 * -------------------------------------------------
 *
 * @author Kazuyuki Hayashi <hayashi@valnur.net>
 */
class StatusCommand extends Command
{

    const UNMODIFIED           = ' ';
    const MODIFIED             = 'M';
    const ADDED                = 'A';
    const DELETED              = 'D';
    const RENAMED              = 'R';
    const COPIED               = 'C';
    const UPDATED_BUT_UNMERGED = 'U';
    const UNTRACKED            = '?';
    const IGNORED              = '!';

    /**
     * Returns the working tree status
     *
     * ``` php
     * $git = new PHPGit\Git();
     * $git->setRepository('/path/to/repo');
     * $status = $git->status();
     * ```
     *
     * ##### Constants
     *
     * - StatusCommand::UNMODIFIED            [=' '] unmodified
     * - StatusCommand::MODIFIED              [='M'] modified
     * - StatusCommand::ADDED                 [='A'] added
     * - StatusCommand::DELETED               [='D'] deleted
     * - StatusCommand::RENAMED               [='R'] renamed
     * - StatusCommand::COPIED                [='C'] copied
     * - StatusCommand::UPDATED_BUT_UNMERGED  [='U'] updated but unmerged
     * - StatusCommand::UNTRACKED             [='?'] untracked
     * - StatusCommand::IGNORED               [='!'] ignored
     *
     * ##### Output Example
     *
     * ``` php
     * [
     *     'branch' => 'master',
     *     'changes' => [
     *         ['file' => 'item1.txt', 'index' => 'A', 'work_tree' => 'M'],
     *         ['file' => 'item2.txt', 'index' => 'A', 'work_tree' => ' '],
     *         ['file' => 'item3.txt', 'index' => '?', 'work_tree' => '?'],
     *     ]
     * ]
     * ```
     *
     * ##### Options
     *
     * - **ignored** (_boolean_) Show ignored files as well
     *
     * @param array $options [optional] An array of options {@see StatusCommand::setDefaultOptions}
     *
     * @return mixed
     */
    public function __invoke(array $options = array())
    {
        $options = $this->resolve($options);
        $builder = $this->git->getProcessBuilder()
            ->add('status')
            ->add('--porcelain')->add('-s')->add('-b')->add('--null');

        $this->addFlags($builder, $options);

        $process = $builder->getProcess();
        $result  = array('branch' => null, 'changes' => array());
        $output  = $this->git->run($process);

        list($branch, $changes) = preg_split('/(\0|\n)/', $output, 2);
        $lines = $this->split($changes, true);

        if (substr($branch, -11) == '(no branch)') {
            $result['branch'] = null;
        } elseif (preg_match('/([^ ]*)\.\.\..*?\[.*?\]$/', $branch, $matches)) {
            $result['branch'] = $matches[1];
        } elseif (preg_match('/ ([^ ]*)$/', $branch, $matches)) {
            $result['branch'] = $matches[1];
        }

        foreach ($lines as $line) {
            $result['changes'][] = array(
                'file'      => substr($line, 3),
                'index'     => substr($line, 0, 1),
                'work_tree' => substr($line, 1, 1)
            );
        }

        return $result;
    }

    /**
     * {@inheritdoc}
     *
     * - **ignored** (_boolean_) Show ignored files as well
     */
    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'ignored' => false
        ));
    }

}