Skip to content

Working copy

Working copy is the folder associated to a git repository. In gitlib, you can access this object using the getWorkingCopy on a Repository object:

use Gitonomy\Git\Repository;

$repo = new Repository('/path/to/working-dir');
$wc = $repo->getWorkingCopy();

A bare repository has no working copy: getWorkingCopy() throws a LogicException.

Checkout a revision

You can checkout any revision using checkout method. Like git checkout, it attaches HEAD to a local branch, or to @{-1}, the branch checked out before (@{-2} the one before...), leaves it as it is for HEAD, and detaches it on anything else: a tag, a commit, a remote branch...

// git checkout master
$wc->checkout('master');

// git checkout v1.0 (HEAD is detached)
$wc->checkout('v1.0');

// git checkout @{-1}: the branch checked out before
$wc->checkout('@{-1}');

You can also pass a Revision: a Commit, a Reference... A local Branch object attaches HEAD to the branch.

$wc->checkout($repo->getReferences()->getBranch('master'));

A name that no revision has throws a ReferenceNotFoundException, with both drivers, unlike git checkout: a path, like README.md, whose changes git would discard, or the name of a remote branch alone, like feature for origin/feature, whose local branch git would create. Create it with checkoutNewBranch.

To create a branch and check it out, use checkoutNewBranch. Its second argument is the revision to start the branch from, HEAD by default:

// git checkout -b feature
$wc->checkoutNewBranch('feature');

// git checkout -b develop origin/develop
$wc->checkoutNewBranch('develop', 'origin/develop');

Like with git checkout -b, a branch created from a remote branch, like origin/develop, tracks it: git pull and git push know its upstream branch. One created from a local branch, a tag or a commit tracks none. gitlib does so whatever the configuration (branch.autoSetupMerge), with both drivers. Like git, checkoutNewBranch refuses a start point several references have the name of, like origin/develop when a local branch has this name too, with a DriverException: use its full name, refs/remotes/origin/develop.

Like git checkout, both methods keep the local changes, and refuse to overwrite the ones the checkout would change: they throw a DriverException. checkoutNewBranch then creates no branch.

Passing the branch to create as second argument of checkout is deprecated since 1.7: use checkoutNewBranch.

Merge a revision

You can merge any revision into the current branch using the merge method. A second argument, a FastForward, tells whether the merge fast-forwards the branch when its history allows it:

use Gitonomy\Git\FastForward;

// git merge origin/develop
$wc->merge('origin/develop');

// git merge --no-ff origin/develop
$wc->merge('origin/develop', FastForward::Never);

// git merge --ff-only origin/develop
$wc->merge('origin/develop', FastForward::Only);

FastForward::Allow, the default, fast-forwards when possible and creates a merge commit otherwise. FastForward::Never always creates a merge commit. FastForward::Only throws instead of creating one.

You can also pass a Revision. Like with checkout, a name that no revision has throws a ReferenceNotFoundException. A DriverException is thrown if the merge fails: a conflict, staged changes, a revision whose history is unrelated to the branch...

With CliDriver, a conflict leaves the working copy merging, with conflict markers in the files, like git merge. To cancel the merge:

$repo->run('merge', ['--abort']);

note

With LibGit2Driver (see Choosing a driver), merge() only supports fast-forward and conflict-free merges: a conflict throws without changing anything, instead of leaving conflict markers in the working copy.

Modifications since a revision

You can get the modifications of the working copy, staged or not, since a revision, HEAD by default:

// git diff HEAD
$diff = $wc->getDiff();

// git diff master
$diff = $wc->getDiff('master');

Calling Repository::getDiff() with one revision, to compare it with the working copy, is deprecated since 1.7: use WorkingCopy::getDiff().

Staged modifications

You can get a diff of modifications pending in staging area. To get the Diff object, call method getDiffStaged():

$diff = $wc->getDiffStaged();

Pending modifications

You can get pending modifications on tracked files, not staged yet, by calling method getDiffPending():

$diff = $wc->getDiffPending();

Like with git 2.19 and later, a file added with git add -N (intent to add) is no staged change: getDiffPending() lists it as created. With CliDriver, older versions of git list it as an empty staged file.

During a merge conflict, getDiffStaged() and getDiffPending() leave the unmerged files out, and getDiff() compares them, conflict markers included, to the revision, like git diff HEAD.

See Diff to read these diffs.

Untracked files

To list the files git doesn't track, ignored files excluded, call getUntrackedFiles(). It returns their paths, relative to the root of the working copy:

$files = $wc->getUntrackedFiles(); // ['new-file.txt', 'new-directory/other-file.txt']