/** * Updates the given path to the given commit ref * * @param string $path * @param string $reference * @param string $branch * @param \DateTime $date * @return null|string if a string is returned, it is the commit reference that was checked out if the original could not be found * * @throws \RuntimeException */ protected function updateToCommit($path, $reference, $branch, $date) { $template = 'git checkout %s && git reset --hard %1$s'; $branch = preg_replace('{(?:^dev-|(?:\\.x)?-dev$)}i', '', $branch); $branches = null; if (0 === $this->process->execute('git branch -r', $output, $path)) { $branches = $output; } // check whether non-commitish are branches or tags, and fetch branches with the remote name $gitRef = $reference; if (!preg_match('{^[a-f0-9]{40}$}', $reference) && $branches && preg_match('{^\\s+composer/' . preg_quote($reference) . '$}m', $branches)) { $command = sprintf('git checkout -B %s %s && git reset --hard %2$s', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/' . $reference)); if (0 === $this->process->execute($command, $output, $path)) { return; } } // try to checkout branch by name and then reset it so it's on the proper branch name if (preg_match('{^[a-f0-9]{40}$}', $reference)) { // add 'v' in front of the branch if it was stripped when generating the pretty name if (!preg_match('{^\\s+composer/' . preg_quote($branch) . '$}m', $branches) && preg_match('{^\\s+composer/v' . preg_quote($branch) . '$}m', $branches)) { $branch = 'v' . $branch; } $command = sprintf('git checkout %s', ProcessExecutor::escape($branch)); $fallbackCommand = sprintf('git checkout -B %s %s', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/' . $branch)); if (0 === $this->process->execute($command, $output, $path) || 0 === $this->process->execute($fallbackCommand, $output, $path)) { $command = sprintf('git reset --hard %s', ProcessExecutor::escape($reference)); if (0 === $this->process->execute($command, $output, $path)) { return; } } } $command = sprintf($template, ProcessExecutor::escape($gitRef)); if (0 === $this->process->execute($command, $output, $path)) { return; } // reference was not found (prints "fatal: reference is not a tree: $ref") if ($date && false !== strpos($this->process->getErrorOutput(), $reference)) { $date = $date->format('U'); // guess which remote branch to look at first $command = 'git branch -r'; if (0 !== $this->process->execute($command, $output, $path)) { throw new \RuntimeException('Failed to execute ' . $command . "\n\n" . $this->process->getErrorOutput()); } $guessTemplate = 'git log --until=%s --date=raw -n1 --pretty=%%H %s'; foreach ($this->process->splitLines($output) as $line) { if (preg_match('{^composer/' . preg_quote($branch) . '(?:\\.x)?$}i', trim($line))) { // find the previous commit by date in the given branch if (0 === $this->process->execute(sprintf($guessTemplate, $date, ProcessExecutor::escape(trim($line))), $output, $path)) { $newReference = trim($output); } break; } } if (empty($newReference)) { // no matching branch found, find the previous commit by date in all commits if (0 !== $this->process->execute(sprintf($guessTemplate, $date, '--all'), $output, $path)) { throw new \RuntimeException('Failed to execute ' . GitUtil::sanitizeUrl($command) . "\n\n" . $this->process->getErrorOutput()); } $newReference = trim($output); } // checkout the new recovered ref $command = sprintf($template, ProcessExecutor::escape($newReference)); if (0 === $this->process->execute($command, $output, $path)) { $this->io->write(' ' . $reference . ' is gone (history was rewritten?), recovered by checking out ' . $newReference); return $newReference; } } throw new \RuntimeException('Failed to execute ' . GitUtil::sanitizeUrl($command) . "\n\n" . $this->process->getErrorOutput()); }
/** * Updates the given path to the given commit ref * * @param string $path * @param string $reference * @param string $branch * @param \DateTime $date * @throws \RuntimeException * @return null|string if a string is returned, it is the commit reference that was checked out if the original could not be found */ protected function updateToCommit($path, $reference, $branch, $date) { $force = $this->hasDiscardedChanges || $this->hasStashedChanges ? '-f ' : ''; // This uses the "--" sequence to separate branch from file parameters. // // Otherwise git tries the branch name as well as file name. // If the non-existent branch is actually the name of a file, the file // is checked out. $template = 'git checkout ' . $force . '%s -- && git reset --hard %1$s --'; $branch = preg_replace('{(?:^dev-|(?:\\.x)?-dev$)}i', '', $branch); $branches = null; if (0 === $this->process->execute('git branch -r', $output, $path)) { $branches = $output; } // check whether non-commitish are branches or tags, and fetch branches with the remote name $gitRef = $reference; if (!preg_match('{^[a-f0-9]{40}$}', $reference) && $branches && preg_match('{^\\s+composer/' . preg_quote($reference) . '$}m', $branches)) { $command = sprintf('git checkout ' . $force . '-B %s %s -- && git reset --hard %2$s --', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/' . $reference)); if (0 === $this->process->execute($command, $output, $path)) { return; } } // try to checkout branch by name and then reset it so it's on the proper branch name if (preg_match('{^[a-f0-9]{40}$}', $reference)) { // add 'v' in front of the branch if it was stripped when generating the pretty name if (!preg_match('{^\\s+composer/' . preg_quote($branch) . '$}m', $branches) && preg_match('{^\\s+composer/v' . preg_quote($branch) . '$}m', $branches)) { $branch = 'v' . $branch; } $command = sprintf('git checkout %s --', ProcessExecutor::escape($branch)); $fallbackCommand = sprintf('git checkout ' . $force . '-B %s %s --', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/' . $branch)); if (0 === $this->process->execute($command, $output, $path) || 0 === $this->process->execute($fallbackCommand, $output, $path)) { $command = sprintf('git reset --hard %s --', ProcessExecutor::escape($reference)); if (0 === $this->process->execute($command, $output, $path)) { return; } } } $command = sprintf($template, ProcessExecutor::escape($gitRef)); if (0 === $this->process->execute($command, $output, $path)) { return; } // reference was not found (prints "fatal: reference is not a tree: $ref") if (false !== strpos($this->process->getErrorOutput(), $reference)) { $this->io->writeError(' <warning>' . $reference . ' is gone (history was rewritten?)</warning>'); } throw new \RuntimeException('Failed to execute ' . GitUtil::sanitizeUrl($command) . "\n\n" . $this->process->getErrorOutput()); }
protected function updateToCommit($path, $reference, $branch, $date) { $template = 'git checkout %s && git reset --hard %1$s'; $branch = preg_replace('{(?:^dev-|(?:\\.x)?-dev$)}i', '', $branch); $branches = null; if (0 === $this->process->execute('git branch -r', $output, $path)) { $branches = $output; } $gitRef = $reference; if (!preg_match('{^[a-f0-9]{40}$}', $reference) && $branches && preg_match('{^\\s+composer/' . preg_quote($reference) . '$}m', $branches)) { $command = sprintf('git checkout -B %s %s && git reset --hard %2$s', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/' . $reference)); if (0 === $this->process->execute($command, $output, $path)) { return; } } if (preg_match('{^[a-f0-9]{40}$}', $reference)) { if (!preg_match('{^\\s+composer/' . preg_quote($branch) . '$}m', $branches) && preg_match('{^\\s+composer/v' . preg_quote($branch) . '$}m', $branches)) { $branch = 'v' . $branch; } $command = sprintf('git checkout %s', ProcessExecutor::escape($branch)); $fallbackCommand = sprintf('git checkout -B %s %s', ProcessExecutor::escape($branch), ProcessExecutor::escape('composer/' . $branch)); if (0 === $this->process->execute($command, $output, $path) || 0 === $this->process->execute($fallbackCommand, $output, $path)) { $command = sprintf('git reset --hard %s', ProcessExecutor::escape($reference)); if (0 === $this->process->execute($command, $output, $path)) { return; } } } $command = sprintf($template, ProcessExecutor::escape($gitRef)); if (0 === $this->process->execute($command, $output, $path)) { return; } if (false !== strpos($this->process->getErrorOutput(), $reference)) { $this->io->writeError(' <warning>' . $reference . ' is gone (history was rewritten?)</warning>'); } throw new \RuntimeException('Failed to execute ' . GitUtil::sanitizeUrl($command) . "\n\n" . $this->process->getErrorOutput()); }