From bce4b23d7e230ab9b30b03fdeb382196ff14592e Mon Sep 17 00:00:00 2001 From: Thomas Zander Date: Fri, 2 May 2008 17:28:55 +0200 Subject: [PATCH] Fix regression since my 'clear index' fix, added files get recorded again --- Add.cpp | 149 ------------------ Add.h | 41 ----- Branches.cpp | 58 ------- Branches.h | 34 ---- Changes.cpp | 179 --------------------- Changes.h | 33 ---- Initialize.cpp | 76 --------- Initialize.h | 33 ---- Move.cpp | 130 --------------- Move.h | 37 ----- Push.cpp | 150 ------------------ Push.h | 34 ---- Record.cpp | 446 ---------------------------------------------------- Record.h | 38 ----- Remove.cpp | 62 -------- Remove.h | 34 ---- Revert.cpp | 127 --------------- Revert.h | 38 ----- UnRecord.cpp | 129 --------------- UnRecord.h | 33 ---- UnRevert.cpp | 106 ------------- UnRevert.h | 33 ---- VngCommandLine.cpp | 24 +-- WhatsNew.cpp | 114 -------------- WhatsNew.h | 33 ---- commands/Record.cpp | 9 +- vng.pro | 48 +++--- 27 files changed, 42 insertions(+), 2186 deletions(-) delete mode 100644 Add.cpp delete mode 100644 Add.h delete mode 100644 Branches.cpp delete mode 100644 Branches.h delete mode 100644 Changes.cpp delete mode 100644 Changes.h delete mode 100644 Initialize.cpp delete mode 100644 Initialize.h delete mode 100644 Move.cpp delete mode 100644 Move.h delete mode 100644 Push.cpp delete mode 100644 Push.h delete mode 100644 Record.cpp delete mode 100644 Record.h delete mode 100644 Remove.cpp delete mode 100644 Remove.h delete mode 100644 Revert.cpp delete mode 100644 Revert.h delete mode 100644 UnRecord.cpp delete mode 100644 UnRecord.h delete mode 100644 UnRevert.cpp delete mode 100644 UnRevert.h delete mode 100644 WhatsNew.cpp delete mode 100644 WhatsNew.h diff --git a/Add.cpp b/Add.cpp deleted file mode 100644 index 40201de..0000000 --- a/Add.cpp +++ /dev/null @@ -1,149 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * Copyright (C) 2002-2004 David Roundy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Add.h" -#include "CommandLineParser.h" -#include "Logger.h" -#include "GitRunner.h" -#include "Vng.h" - -#include -#include -#include - -static const CommandLineOption options[] = { - {"-r, --recursive", "recursively add files"}, - {"--not-recursive", "do not add files in directories recursively"}, - {"-f, --boring", "don't skip boring files"}, - CommandLineLastOption -}; - -Add::Add() - : AbstractCommand("add"), - m_excludeMatcher(m_config) -{ - CommandLineParser::addOptionDefinitions(options); - CommandLineParser::setArgumentDefinition("add " ); -} - -AbstractCommand::ReturnCodes Add::run() -{ - if (! checkInRepository()) - return NotInRepo; - moveToRoot(); - CommandLineParser *args = CommandLineParser::instance(); - const bool recursive = !m_config.contains("not-recursive") && !args->contains("not-recursive"); - - int argIndex = 0; - foreach(QString arg, rebasedArguments()) { - ++argIndex; - QFileInfo path(arg); - if (! arg.endsWith('/') && path.isDir()) - arg = arg + '/'; - if (!args->contains("boring") && m_excludeMatcher.isExcluded(arg)) { - Logger::warn() << "Skipping boring file: `" << args->arguments()[argIndex] << "'\n"; - continue; - } - if (path.exists()) { - if (path.isFile()) { - ReturnCodes rc = addFile(path, true); - if (rc != Ok) - return rc; - } - else if (path.isDir()) { - if (recursive) - recurse(QDir(arg)); - } - else if (path.isSymLink()) - Logger::warn() << "Ignoring symbolic link '" << path.filePath() << "'" << endl; - else - Logger::warn() << "Ignoring non-file object '" << path.filePath() << "'" << endl; - } - else - Logger::error() << "Can not add non existing' " << path.filePath() << "'" << endl; - } - return Ok; -} - -QString Add::argumentDescription() const -{ - return ""; -} - -QString Add::commandDescription() const -{ - return "Add needs to be called whenever you add a new file or directory to your\n" - "project. Of course, it also needs to be called when you first create the\n" - "project, to let vng know which files should be kept track of.\n"; -} - -AbstractCommand::ReturnCodes Add::addFile(const QFileInfo &path, bool warn) -{ - - QProcess checker; - QStringList arguments; - arguments << "ls-files" << path.filePath(); - GitRunner runner(checker, arguments); - ReturnCodes rc = runner.start(GitRunner::WaitForStandardOutput); - if (rc != Ok) - return rc; - bool shouldAdd = true; - char buf[1024]; - while(true) { - qint64 lineLength = Vng::readLine(&checker, buf, sizeof(buf)); - if (lineLength == -1) - break; - shouldAdd = false; // lets assume here that the script just doesn't print anything if its not added yet. - break; - } - if (! shouldAdd) { - warn ? Logger::warn() : Logger::info() << "Not adding file, already in the repository: `" << path.filePath() << "'\n"; - checker.waitForFinished(); - return Ok; - } - Logger::warn() << "Adding '" << path.filePath() << "'" << endl; - if (dryRun()) - return Ok; - QProcess git; - arguments.clear(); - arguments << "update-index" << "--add" << path.filePath(); - GitRunner runner2(git, arguments); - rc = runner2.start(GitRunner::WaitUntilFinished); - return rc; -} - -void Add::recurse(const QDir &dir) -{ - CommandLineParser *args = CommandLineParser::instance(); - foreach(QFileInfo file, dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot)) { - if (!args->contains("boring")) { - QString path = file.filePath(); - if (file.isDir()) - path += '/'; - if (m_excludeMatcher.isExcluded(path)) { - Logger::info() << "Skipping boring " << (file.isDir() ? "directory": "file") << "`" << file.filePath() << "'\n"; - continue; - } - } - if(file.isDir()) - recurse(QDir(file.filePath())); - else if (file.isFile()) - addFile(file, false); - } -} diff --git a/Add.h b/Add.h deleted file mode 100644 index f3db6ba..0000000 --- a/Add.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef ADD_H -#define ADD_H - -#include "AbstractCommand.h" -#include "ExcludeMatcher.h" - -class Add : public AbstractCommand { -public: - Add(); - -protected: - virtual QString argumentDescription() const; - virtual ReturnCodes run(); - virtual QString commandDescription() const; - -private: - ReturnCodes addFile(const QFileInfo &path, bool warn); - void recurse(const QDir &dir); - - ExcludeMatcher m_excludeMatcher; -}; - -#endif diff --git a/Branches.cpp b/Branches.cpp deleted file mode 100644 index 83a2adb..0000000 --- a/Branches.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Branches.h" -#include "CommandLineParser.h" -#include "Logger.h" -// #include "GitRunner.h" -// #include "Vng.h" - -// #include -// #include - -static const CommandLineOption options[] = { - // TODO :) - CommandLineLastOption -}; - -Branches::Branches() - : AbstractCommand("branches") -{ - CommandLineParser::addOptionDefinitions(options); -} - -AbstractCommand::ReturnCodes Branches::run() -{ - if (! checkInRepository()) - return NotInRepo; - - foreach(Branch branch, m_config.allBranches()) { - Logger::standardOut() << branch.branchName() << endl; - } - return Ok; -} - -QString Branches::argumentDescription() const -{ - return QString(); -} - -QString Branches::commandDescription() const -{ - return ""; // TODO -} diff --git a/Branches.h b/Branches.h deleted file mode 100644 index ee0b494..0000000 --- a/Branches.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef BRANCHES_H -#define BRANCHES_H - -#include "AbstractCommand.h" - -class Branches : public AbstractCommand { -public: - Branches(); - -protected: - virtual QString argumentDescription() const; - virtual ReturnCodes run(); - virtual QString commandDescription() const; -}; - -#endif diff --git a/Changes.cpp b/Changes.cpp deleted file mode 100644 index e8c4d2d..0000000 --- a/Changes.cpp +++ /dev/null @@ -1,179 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * Copyright (C) 2002-2004 David Roundy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include "Changes.h" -#include "CommandLineParser.h" -#include "GitRunner.h" -#include "Logger.h" -#include "Vng.h" -#include "hunks/ChangeSet.h" -#include "commits/Commit.h" -#include "commits/CommitsMatcher.h" - - -static const CommandLineOption options[] = { - // {"-a, --all", "answer yes to all patches"}, - {"--to-match PATTERN", "select changes up to a patch matching PATTERN"}, - {"--to-patch REGEXP", "select changes up to a patch matching REGEXP"}, - // {"--to-tag REGEXP", "select changes up to a tag matching REGEXP"}, - {"--from-match PATTERN", "select changes starting with a patch matching PATTERN"}, - {"--from-patch REGEXP", "select changes starting with a patch matching REGEXP"}, - // {"--from-tag REGEXP", "select changes starting with a tag matching REGEXP"}, - {"-n, --last NUMBER", "select the last NUMBER patches"}, - {"--match PATTERN", "select patches matching PATTERN"}, - {"-p, --patches REGEXP", "select patches matching REGEXP"}, - // {"-t, --tags=REGEXP", "select tags matching REGEXP"}, - // {"--context", "give output suitable for get --context"}, - // {"--xml-output", "generate XML formatted output"}, - // {"--human-readable", "give human-readable output"}, - {"-s, --summary", "summarize changes"}, - {"--no-summary", "don't summarize changes"}, - // {"--reverse", "show changes in reverse order"}, - CommandLineLastOption -}; - -Changes::Changes() - : AbstractCommand("changes") -{ - CommandLineParser::addOptionDefinitions(options); - CommandLineParser::setArgumentDefinition("changes [FILE or DIRECTORY]" ); -} - -QString Changes::argumentDescription() const -{ - return "[FILE or DIRECTORY]"; -} - -QString Changes::commandDescription() const -{ - return "Gives a changelog-style summary of the repository history.\n"; -} - -AbstractCommand::ReturnCodes Changes::run() -{ - if (! checkInRepository()) - return NotInRepo; - CommandLineParser *args = CommandLineParser::instance(); - - QProcess git; - QStringList arguments; - arguments << "whatchanged" << "-m" << "--pretty=raw"; - - if (args->contains("last")) - arguments << "-n" << args->optionArgument("last"); - - QList usedArguments; - usedArguments << 0; - foreach (Branch branch, m_config.allBranches()) { - QString branchName = branch.branchName(); - if (branchName.endsWith("/HEAD")) - continue; - bool first = true; - int index = -1; - foreach (QString arg, args->arguments()) { - index++; - if (first) { - first = false; // skip command, args for this command are next. - continue; - } - if (branchName == arg || branchName.endsWith(arg) && branchName[branchName.length() - arg.length() - 1] == '/') { - arguments << branchName; - usedArguments << index; - break; - } - } - } - - // now we have to use the rest of the arguments the user passed. - int index = 0; - QStringList unknownArguments; - foreach (QString arg, args->arguments()) { - if (! usedArguments.contains(index++)) { - arguments << arg; - unknownArguments << arg; - } - } - - GitRunner runner(git, arguments); - ReturnCodes rc = runner.start(GitRunner::WaitForStandardOutput); - if (rc) { - Logger::error() << "Vng failed: Unknown branch or revision: "; - foreach(QString arg, unknownArguments) - Logger::error() << "`" << arg << "' ";; - Logger::error() << endl; - return rc; - } - if (shouldUsePager()) - Logger::startPager(); - - const bool showSummery = m_config.contains("summary") && !args->contains("no-summary") || args->contains("summary"); - QTextStream &out = Logger::standardOut(); - CommitsMatcher matcher; - while(true) { - Commit commit = Commit::createFromStream(&git); - if (! commit.isValid()) - break; - switch(matcher.match(commit)) { - case CommitsMatcher::SkipPatch: continue; - case CommitsMatcher::ShowPatch: break; - case CommitsMatcher::Exit: - Logger::stopPager(); - git.waitForFinished(); - return Ok; - } - - out << commit.commitTime().toString() << " "; - m_config.colorize(out); - out << commit.author() << endl; - m_config.normalColor(out); - out << " ID " << commit.commitTreeIsm() << endl; - out << commit.logMessage(); - if (Logger::verbosity() >= Logger::Verbose || showSummery) { - out << endl; - ChangeSet cs = commit.changeSet(); - cs.generateHunks(); - foreach (File file, cs.files()) { - if (file.oldFileName().isEmpty()) - out <<" A " << file.fileName(); - else if (file.fileName().isEmpty()) - out <<" D " << file.oldFileName(); - else - out <<" M " << file.fileName(); - if (Logger::verbosity() < Logger::Verbose) { - if (file.linesRemoved() > 0) - out << " -" << file.linesRemoved(); - if (file.linesAdded() > 0) - out << " +" << file.linesAdded(); - } - out << endl; - if (Logger::verbosity() >= Logger::Verbose) - file.outputWhatsChanged(out, m_config, false, false); - } - } - out << endl; - Logger::flushPager(); - if (! out.device()->isWritable()) { // output cancelled; lets kill git. - git.kill(); - break; - } - } - Logger::stopPager(); - git.waitForFinished(); - return Ok; -} - diff --git a/Changes.h b/Changes.h deleted file mode 100644 index 9d183b1..0000000 --- a/Changes.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#ifndef CHANGES_H -#define CHANGES_H - -#include "AbstractCommand.h" - -class Changes : public AbstractCommand { -public: - Changes(); - -protected: - virtual QString argumentDescription() const; - virtual ReturnCodes run(); - virtual QString commandDescription() const; -}; - -#endif diff --git a/Initialize.cpp b/Initialize.cpp deleted file mode 100644 index b8656e1..0000000 --- a/Initialize.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * Copyright (C) 2003-2005 David Roundy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include "Initialize.h" - -#include "Vng.h" -#include "GitRunner.h" -#include "Logger.h" - -// #include - -Initialize::Initialize() - :AbstractCommand("initialize") -{ -} - -QString Initialize::argumentDescription() const -{ - return QString(); -} - -QString Initialize::commandDescription() const -{ - return "Generally you will only call initialize once for each project you work on,\n" - "and calling it is just about the first thing you do. Just make sure\n" - "you are in the main directory of the project, and initialize will set up all\n" - "the directories and files darcs needs in order to start keeping track of\n" - "revisions for your project.\n"; -} - -AbstractCommand::ReturnCodes Initialize::run() -{ - QProcess git; - QStringList arguments; - arguments << "init" << "--quiet"; - GitRunner runner(git, arguments); - runner.start(GitRunner::WaitForStandardError); - - char buf[1024]; - qint64 lineSize = Vng::readLine(&git, buf, sizeof(buf)); - git.waitForFinished(); - if (git.exitCode() != 0) { - Logger::error() << "Failed to initialize the repo. Do you have writing rights in the current directory?\n"; - Logger::info() << "initialize tries to create a directory '.git` in the current directory\n"; - if (lineSize > 0) - Logger::debug() << "Git said; " << buf; - return WriteError; - } - - Configuration newConfig("initialize"); - newConfig.repositoryMetaDir().mkpath("info"); - QFile file(newConfig.repositoryMetaDir().path() + "/info/exclude"); - if (! file.open(QIODevice::WriteOnly)) - return Ok; // silently ignore, its not that important... - - const char *ignoreContents = "*.o\n.git/*\n.*.sw[po]\n*.o.cmd\n# *.ko files aren't boring by default because they might\n# be Korean translations rather than kernel modules.\n#*.ko\n*.ko.cmd\n*.mod.c\n_darcs/*\nCVS/*\n.svn/*\nRCS/*\n*.bak\n*.BAK\n*.orig\n*vssver.scc\nMT/*\n*.class\n*.prof\n*.DS_Store\nBitKeeper/*\nChangeSet/*\n*.py[co]\n.cvsignore\nThumbs.db\n*autom4te.cache\n"; - file.write(ignoreContents, strlen(ignoreContents)); - file.close(); - return Ok; -} - diff --git a/Initialize.h b/Initialize.h deleted file mode 100644 index e112c51..0000000 --- a/Initialize.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#ifndef INITIALIZE_H -#define INITIALIZE_H - -#include "AbstractCommand.h" - -class Initialize : public AbstractCommand { -public: - Initialize(); - -protected: - virtual QString argumentDescription() const; - virtual ReturnCodes run(); - virtual QString commandDescription() const; -}; - -#endif diff --git a/Move.cpp b/Move.cpp deleted file mode 100644 index 9351605..0000000 --- a/Move.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * Copyright (C) 2002-2004 David Roundy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Move.h" -#include "CommandLineParser.h" -#include "Logger.h" -#include "GitRunner.h" -#include "hunks/File.h" - -#include - -Move::Move() - : AbstractCommand("mv") -{ - CommandLineParser::setArgumentDefinition("mv [FILE or DIRECTORY]" ); -} - -AbstractCommand::ReturnCodes Move::run() -{ - if (! checkInRepository()) - return NotInRepo; - moveToRoot(); - // Move in git is really remove and add. Git will auto detect that being a move. - - typedef QPair RenamePair; - - QList renamePairs; - QStringList files = rebasedArguments(); - if (files.count() < 2) { // not sure what that would mean... - Logger::error() << "Vng failed: you must specify at least two arguments for mv\n"; - return InvalidOptions; - } - QString target = files.takeLast(); - QFileInfo path(target); - if (files.count() > 1) { // multiple files into a dir. - if (! path.isDir()) { - Logger::error() << "Vng failed: The target directory '" << target << - "` does not seem to be an existing directory\n"; - return InvalidOptions; - } - } - else { // target is a file - if(File::fileKnownToGit(path)) { - Logger::error() << "Vng failed: The file named '"<< target << - "` already exists in working directory.\n"; - return InvalidOptions; - } - } - foreach (QString arg, files) { - if (canMoveFile(arg)) { - if (files.count() > 1) - renamePairs.append(qMakePair(arg, target + QDir::separator() + arg)); - else - renamePairs.append(qMakePair(arg, target)); - } - } - - if (dryRun()) - return Ok; - - QProcess git; - QStringList arguments; - arguments << "update-index" << "--add" << "--remove"; - foreach(RenamePair p, renamePairs) { - Logger::debug() << "rename " << p.first << " => " << p.second << endl; - if (QFile::rename(p.first, p.second)) - arguments << p.first << p.second; - else - Logger::error() << "Vng failed: Could not rename '" << p.first << "` to '" << - p.second << "`, check permissions\n"; - } - - if (arguments.count() == 3) { // no files! - Logger::warn() << "Nothing done\n"; - return Ok; - } - GitRunner runner(git, arguments); - return runner.start(GitRunner::WaitUntilFinished); -} - -bool Move::canMoveFile(const QString &file) -{ - QFileInfo path(file); - if (path.exists()) { - if (path.isFile()) { - bool knownToGit = File::fileKnownToGit(path); - if (! knownToGit) { - Logger::warn() << "Not moving file, its not added in the repository: `" << path.filePath() << "'\n"; - return false; - } - return true; - } - else if (path.isSymLink()) - Logger::warn() << "Ignoring symbolic link '" << path.filePath() << "'" << endl; - else - Logger::warn() << "Ignoring non-file object '" << path.filePath() << "'" << endl; - } - else - Logger::error() << "Can not move non existing' " << path.filePath() << "'" << endl; - return false; -} - -QString Move::argumentDescription() const -{ - return ""; -} - -QString Move::commandDescription() const -{ - return "Vng mv can be called whenever you want to move files or\n" - "directories. Unlike remove, mv actually performs the move itself in your\n" - "working copy.\n"; -} - diff --git a/Move.h b/Move.h deleted file mode 100644 index 6305412..0000000 --- a/Move.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef MOVE_H -#define MOVE_H - -#include "AbstractCommand.h" - -class Move : public AbstractCommand { -public: - Move(); - -protected: - virtual QString argumentDescription() const; - virtual ReturnCodes run(); - virtual QString commandDescription() const; - -private: - bool canMoveFile(const QString &fileName); -}; - -#endif diff --git a/Push.cpp b/Push.cpp deleted file mode 100644 index 003057d..0000000 --- a/Push.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Push.h" -#include "CommandLineParser.h" -#include "Logger.h" -#include "GitRunner.h" -#include "Vng.h" - -#include -#include -#include - -static const CommandLineOption options[] = { - // TODO :) - // {"--matches=PATTERN", "select patches matching PATTERN"}, - // {"-p REGEXP, --patches=REGEXP", "select patches matching REGEXP"}, - // {"-t REGEXP, --tags=REGEXP", "select tags matching REGEXP"}, - // {"-a, --all", "answer yes to all patches"}, - // {"-i, --interactive", "prompt user interactively"}, - // {"-s, --summary", "summarize changes"}, - // {"--no-summary", "don't summarize changes"}, - {"--set-default", "set default repository [DEFAULT]"}, - {"--no-set-default", "don't set default repository"}, - CommandLineLastOption -}; - -Push::Push() - : AbstractCommand("Push") -{ - CommandLineParser::addOptionDefinitions(options); - CommandLineParser::setArgumentDefinition("push [ReturnCodes]" ); -} - -AbstractCommand::ReturnCodes Push::run() -{ - if (! checkInRepository()) - return NotInRepo; - CommandLineParser *args = CommandLineParser::instance(); - - QProcess git; - QStringList arguments; - arguments << "config" << "-l"; - GitRunner runner(git, arguments); - AbstractCommand::ReturnCodes rc = runner.start(GitRunner::WaitForStandardOutput); - if (rc != Ok) { - Logger::error() << "Failed to read configuration\n"; - return rc; - } - - QRegExp re("remote\\.(.*)url=(.*)\n"); - QHash repoNames; - char buf[1024]; - while (true) { //read relevant lines into repoNames hash - qint64 length = Vng::readLine(&git, buf, sizeof(buf)); - if (length < 0) - break; - QString line(buf); - if (re.exactMatch(line)) { - QString context = re.cap(1); - if (context.endsWith(".")) - context = context.left(context.length()-1); - repoNames.insert(context, re.cap(2)); - } - } - - QString repo(""); - if (args->arguments().count() > 1) - repo = args->arguments()[1]; - - QString url = repo; - if (repo.isEmpty()) - repo = "default"; // the name we store the default as. - if (repoNames.contains(repo)) - url = repoNames[repo]; - if (url.isEmpty()) { // print help - Logger::standardOut() << "failed: Missing argument [REPOSITORY]\n"; - Logger::standardOut().flush(); - args->usage(name(), argumentDescription()); - Logger::standardOut() << endl << commandDescription(); - return Ok; - } - - Logger::warn() << "Pushing to `" << url << "'\n"; - Logger::warn().flush(); // make sure its printed before git asks for an ssh pwd. - if (dryRun()) - return Ok; - - // TODO when not using --all ask the remote for all the refs it has and detect which ones we still have to push - // TODO use interview to ask which refs to push instead of all below - arguments.clear(); - arguments << "push" << url; - runner.setArguments(arguments); - rc = runner.start(GitRunner::WaitForStandardOutput); - if (rc != Ok) { - Logger::error() << "Git push failed\n"; - return rc; - } - -/* TODO for some reason qprocess doesn't give me any output if the child process already finished :( - while (true) { - qint64 length = Vng::readLine(&git, buf, sizeof(buf)); - if (length < 0) - break; - Logger::info() << QString(buf); - } -*/ - git.waitForFinished(-1); - - if ( !(args->contains("no-set-default") - || m_config.contains("no-set-default") && ! args->contains("set-default")) - && repo == url) { // lets set as default - arguments.clear(); - arguments << "config" << "--add" << "remote.default.url" << repo; - runner.setArguments(arguments); - rc = runner.start(GitRunner::WaitUntilFinished); - if (rc != Ok) { - Logger::error() << "Warning; Failed to store the default value\n"; - return rc; - } - } - - return Ok; -} - -QString Push::argumentDescription() const -{ - return "[REPOSITORY]"; -} - -QString Push::commandDescription() const -{ - return "Push is the opposite of pull. Push allows you to copy changes from the\n" - "current repository into another repository.\n"; -} diff --git a/Push.h b/Push.h deleted file mode 100644 index 1530914..0000000 --- a/Push.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef PUSH_H -#define PUSH_H - -#include "AbstractCommand.h" - -class Push : public AbstractCommand { -public: - Push(); - -protected: - virtual QString argumentDescription() const; - virtual ReturnCodes run(); - virtual QString commandDescription() const; -}; - -#endif diff --git a/Record.cpp b/Record.cpp deleted file mode 100644 index 09b83c0..0000000 --- a/Record.cpp +++ /dev/null @@ -1,446 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * Copyright (C) 2002-2004 David Roundy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include "Record.h" -#include "CommandLineParser.h" -#include "GitRunner.h" -#include "hunks/ChangeSet.h" -#include "hunks/HunksCursor.h" -#include "Logger.h" -#include "Interview.h" -#include "Vng.h" - -#include -#include - -#ifdef Q_OS_WIN -# include -# define getpid() rand() -#else -# include -# include -#endif - - -static const CommandLineOption options[] = { - {"-a, --all", "answer yes to all patches"}, - {"-i, --interactive", "prompt user interactively"}, - {"-m, --patch-name PATCHNAME", "name of patch"}, - {"-A, --author EMAIL", "specify author id"}, - //{"--logfile FILE", "give patch name and comment in file"}, - //{"--delete-logfile", "delete the logfile when done"}, - //{"--no-test", "don't run the test script"}, - //{"--test", "run the test script"}, - //{"--leave-test-directory", "don't remove the test directory"}, - //{"--remove-test-directory", "remove the test directory"}, - //{"--edit-long-comment", "Edit the long comment by default"}, - //{"--skip-long-comment", "Don't give a long comment"}, - //{"--prompt-long-comment", "Prompt for whether to edit the long comment"}, - //{"-l, --look-for-adds", "Also look for files that are potentially pending addition"}, - //{"--dont-look-for-adds", "Don't look for any files that could be added"}, - //{"--umask UMASK", "specify umask to use when writing."}, - //{"--posthook COMMAND", "specify command to run after this vng command."}, - //{"--no-posthook", "Do not run posthook command."}, - //{"--prompt-posthook", "Prompt before running posthook. [DEFAULT]"}, - //{"--run-posthook", "Run posthook command without prompting."}, - CommandLineLastOption -}; - -static AbstractCommand::ReturnCodes copyFile(QIODevice &from, QIODevice &to) { - to.open(QIODevice::WriteOnly); - char buf[4096]; - while (true) { - from.waitForReadyRead(-1); - qint64 len = from.read(buf, sizeof(buf)); - if (len <= 0) { // done! - to.close(); - break; - } - while(len > 0) { - qint64 written = to.write(buf, len); - if (written == -1) // write error! - return AbstractCommand::WriteError; - len -= written; - } - } - return AbstractCommand::Ok; -} - - -Record::Record() - : AbstractCommand("record") -{ - CommandLineParser::addOptionDefinitions(options); - CommandLineParser::setArgumentDefinition("record [FILE or DIRECTORY]" ); -} - -QString Record::argumentDescription() const -{ - return "[FILE or DIRECTORY]"; -} - -QString Record::commandDescription() const -{ - return "Record is used to name a set of changes and record the patch to the repository.\n"; -} - -AbstractCommand::ReturnCodes Record::run() -{ - if (! checkInRepository()) - return NotInRepo; - moveToRoot(); - - CommandLineParser *args = CommandLineParser::instance(); - const bool all = m_config.isEmptyRepo() || m_config.contains("all") - && !args->contains("interactive") || args->contains("all"); - - ChangeSet changeSet; - changeSet.fillFromCurrentChanges(rebasedArguments()); - - bool shouldDoRecord = changeSet.count() > 0; - if (!shouldDoRecord) { - Logger::warn() << "No changes!" << endl; - return Ok; - } - - QString email = args->optionArgument("author", m_config.optionArgument("author", getenv("EMAIL"))); - QStringList environment; - if (! email.isEmpty()) { - QRegExp re("(.*) <([@\\S]+)>"); - if (re.exactMatch(email)) { // meaning its an email AND name - environment << "GIT_AUTHOR_NAME="+ re.cap(1); - environment << "GIT_AUTHOR_EMAIL="+ re.cap(2); - } - else if (!args->contains("author")) // if its an account or shell wide option; just use the git defs. - environment << "GIT_AUTHOR_EMAIL="+ email; - else { - Logger::error() << "Author format invalid. Please provide author formatted like; `name \n"; - return InvalidOptions; - } - } - - if (shouldDoRecord && !all) { // then do interview - HunksCursor cursor(changeSet); - cursor.setConfiguration(m_config); - Interview interview(cursor, name()); - interview.setUsePager(shouldUsePager()); - if (! interview.start()) { - Logger::warn() << "Record cancelled." << endl; - return Ok; - } - } - - if (shouldDoRecord && !all) { // check if there is anything selected - shouldDoRecord = changeSet.hasAcceptedChanges(); - if (! shouldDoRecord) { - Logger::warn() << "Ok, if you don't want to record anything, that's fine!" <optionArgument("patch-name", m_config.optionArgument("patch-name")).toUtf8(); - if (dryRun()) - return Ok; - - if (patchName.isEmpty() && getenv("EDITOR")) { - class Deleter : public QObject { - public: - Deleter() : commitMessage(0) { } - ~Deleter() { - if (commitMessage) - commitMessage->remove(); - } - QFile *commitMessage; - }; - Deleter parent; - QFile *commitMessage; - int i = 0; - do { - commitMessage = new QFile(QString("vng-record-%1").arg(i++), &parent); - } while (commitMessage->exists()); - parent.commitMessage = commitMessage; // make sure the file is removed from FS. - if (! commitMessage->open(QIODevice::WriteOnly)) { - Logger::error() << "vng-failed. Could not create a temporary file for the record message '" - << commitMessage->fileName() << "`\n"; - return WriteError; - } - const char * defaultCommitMessage1 = "\n***END OF DESCRIPTION***"; // we will look for this string later - const char * defaultCommitMessage2 = "\nPlace the long patch description above the ***END OF DESCRIPTION*** marker.\n\nThis patch contains the following changes:\n"; - commitMessage->write("\n", 1); - commitMessage->write(defaultCommitMessage1, strlen(defaultCommitMessage1)); - commitMessage->write(defaultCommitMessage2, strlen(defaultCommitMessage2)); - QBuffer buffer; - changeSet.writeDiff(buffer, ChangeSet::UserSelection); - ChangeSet actualChanges; - actualChanges.fillFromDiffFile(buffer); - QTextStream out (commitMessage); - foreach (File file, actualChanges.files()) - file.outputWhatsChanged(out, m_config, true, false); - out.flush(); - - commitMessage->close(); - QDateTime modification = QFileInfo(*commitMessage).lastModified(); - QString command = QString("%1 %2").arg(getenv("EDITOR")).arg(commitMessage->fileName()); - int rc = system(command.toAscii().data()); - if (rc != 0) { - // this will keep patchName empty and we fall through to the interview. - Logger::warn() << "Vng-Warning: Could not start editor '" << getenv("EDITOR") << "`\n"; - Logger::warn().flush(); - } - else if (modification == QFileInfo(*commitMessage).lastModified()) { - Logger::warn() << "unchanged, won't record\n"; - return Ok; - } - else { - // get data until the separator line. - commitMessage->open(QIODevice::ReadOnly); - patchName = commitMessage->readAll(); - commitMessage->close(); - int cuttoff = patchName.indexOf(defaultCommitMessage1); - if (cuttoff > 0) - patchName.truncate(cuttoff); - } - } - if (patchName.isEmpty()) - patchName = Interview::ask("What is the patch name? ").toUtf8(); - - // first clean out the index so that previous stuff other tools did doesn't influence us. - QProcess git; - QStringList arguments; - arguments << "read-tree" << "--aggressive" << "HEAD"; - GitRunner runner(git, arguments); - ReturnCodes rc = runner.start(GitRunner::WaitUntilFinished); - if (rc != Ok) { - Logger::error() << "internal error; failed to initialize record, sorry, aborting record\n"; - return rc; - } - - rc = addFilesPerAcceptance(changeSet, all); - if (rc != Ok) - return rc; - - arguments.clear(); - arguments << "write-tree"; - runner.setArguments(arguments); - rc = runner.start(GitRunner::WaitForStandardOutput); - if (rc != Ok) { - Logger::error() << "Git write-tree failed!, aborting record\n"; - return rc; - } - char buf[1024]; - Vng::readLine(&git, buf, sizeof(buf)); - QString tree(buf); - git.waitForFinished(); // patiently wait for it to finish.. - Logger::debug() << "The tree got git ref; " << tree; - Logger::debug().flush(); // flush since we do an ask next - - arguments.clear(); - git.setEnvironment(environment); - // TODO - // if amend then; - // parent = git-cat-file commit HEAD | grep parent - // if .git/MERGE_HEAD exists its a merge - // then we have multiple heads, one additional per line in .git/MERGE_HEAD - // also use .git/MERGE_MSG - - arguments << "commit-tree" << tree.left(40); - if (!m_config.isEmptyRepo()) - arguments << "-p" << "HEAD" ; - - runner.setArguments(arguments); - rc = runner.start(GitRunner::WaitUntilReadyForWrite); - if (rc != Ok) { - Logger::error() << "Git commit-tree failed!, aborting record\n"; - return rc; - } - git.write(patchName); - git.write("\n"); - git.closeWriteChannel(); - Vng::readLine(&git, buf, sizeof(buf)); - QString commit(buf); - Logger::debug() << "commit is ref; " << commit; - git.waitForFinished(); // patiently wait for it to finish.. - if (commit.isEmpty()) { - Logger::error() << "Git update-ref failed to produce a reference!, aborting record\n"; - return GitFailed; - } - - arguments.clear(); - arguments << "update-ref" << "HEAD" << commit.left(40); - runner.setArguments(arguments); - rc = runner.start(GitRunner::WaitUntilFinished); - if (rc != Ok) { - Logger::error() << "Git update-ref failed!, aborting record\n"; - return rc; - } - - // We removed files from the index in case they were freshly added, but the user didn't want it in this commit. - // we have to re-add those files. - arguments.clear(); - arguments << "update-index" << "--add"; - foreach (File file, changeSet.files()) { - if (! file.oldFileName().isEmpty()) - continue; // not a new added file. - if (file.renameAcceptance() == Vng::Rejected) - arguments.append(file.fileName()); - } - if (arguments.count() > 2) { - runner.setArguments(arguments); - runner.start(GitRunner::WaitUntilFinished); - } - - int endOfLine = patchName.indexOf('\n'); - if (endOfLine > 0) - patchName.truncate(endOfLine); - Logger::warn() << "Finished recording patch `" << patchName << "'" << endl; - return Ok; -} - -AbstractCommand::ReturnCodes Record::addFilesPerAcceptance(const ChangeSet &changeSet, bool allChanges) -{ - typedef QPair NamePair; - class RevertCopier { - public: - RevertCopier() {} - ~RevertCopier() { - foreach(NamePair pair, m_fileNames) { - QFile copy(pair.second); - copy.remove(); - if (! pair.first.isEmpty()) { - QFile orig(pair.first); - orig.rename(copy.fileName()); - } - } - } - void append(const QString &orig, const QString ©) { - QPair pair(orig, copy); - m_fileNames.append(pair); - } - private: - // thats orig, copy - QList< QPair > m_fileNames; - }; - RevertCopier reverter;// this will revert all file changes we make when we exit the scope of this method. - ChangeSet patchChanges; - - QStringList filesForAdd; - foreach (File file, changeSet.files()) { - bool someEnabled = false; - bool allEnabled = true; - const bool renamed = file.fileName() != file.oldFileName(); - const bool protectionChanged = !renamed && file.protection() != file.oldProtection(); - if (file.renameAcceptance() == Vng::Accepted && renamed - || file.protectionAcceptance() == Vng::Accepted && protectionChanged) // record it. - someEnabled = true; - - foreach (Hunk hunk, file.hunks()) { - Vng::Acceptance a = hunk.acceptance(); - if (a == Vng::Accepted || a == Vng::MixedAcceptance) - someEnabled = true; - else - allEnabled = false; - if (someEnabled && !allEnabled) - break; - } - const bool removeFromIndex = !allChanges && !someEnabled; // user said 'no', lets make sure none of the changes are left in the index. - if (removeFromIndex && ! file.fileName().isEmpty() && ! file.oldFileName().isEmpty()) // just ignore file. - continue; - const bool addUnaltered = allChanges || allEnabled; - Logger::debug() << file.fileName() << "] addUnaltered: " << addUnaltered << ", removeFromIndex: " - << removeFromIndex << ", someChangesAccepted: " << someEnabled << ", allAccepted: " << allEnabled << endl; - if (file.fileName().isEmpty()) - filesForAdd << file.oldFileName(); - else - filesForAdd << file.fileName(); - - if (addUnaltered) - continue; // thats easy; whole file to add. - if (removeFromIndex && file.fileName().isEmpty()) { // user said no about recording a deleted file. - // this is a funny situation; *just* in case the user already somehow added the deletion to the index - // we need to reset that to make the index have the full file again. Notice that we need to remove the file afterwards. - Q_ASSERT(!file.oldFileName().isEmpty()); - QProcess git; - QStringList arguments; - arguments << "cat-file" << "blob" << file.oldSha1(); - GitRunner runner(git, arguments); - ReturnCodes rc = runner.start(GitRunner::WaitForStandardOutput); - if (rc == Ok) { - reverter.append(QString(), file.oldFileName()); - QFile deletedFile(file.oldFileName()); - Q_ASSERT(! deletedFile.exists()); - deletedFile.open(QIODevice::WriteOnly); - rc = copyFile(git, deletedFile); - git.waitForFinished(); - deletedFile.close(); - if (rc) - return rc; - } - continue; - } - - // for the case where only some patches are selected we make a safety copy of the file. - QFile sourceFile(file.fileName()); - Q_ASSERT(sourceFile.exists()); - QString fileName = file.fileName(); - for(int i=0; i < 10; i++) { - fileName = fileName + ".orig"; - if (sourceFile.rename(fileName)) - break; // successful! - } - reverter.append(fileName, file.fileName()); - if (removeFromIndex) // need to rename it only, we won't patch it. - continue; - - patchChanges.addFile(file); - Logger::debug() << "cp " << fileName << " =>" << file.fileName() << endl; - QFile orig(fileName); - orig.open(QIODevice::ReadOnly); - copyFile(orig, sourceFile); - sourceFile.setPermissions(file.permissions()); - } - - QFile patch(".vng.record." + QString::number(getpid()) + ".diff"); - patchChanges.writeDiff(patch, ChangeSet::InvertedUserSelection); - patch.close(); - - if (patch.size() != 0) { - QProcess git; - QStringList arguments; - arguments << "apply" << "--apply" << "--reverse" << patch.fileName(); - GitRunner runner(git, arguments); - ReturnCodes rc = runner.start(GitRunner::WaitUntilFinished); - if (rc != Ok) { - Logger::error() << "internal error; failed to patch, sorry, aborting record\n"; - return rc; // note that copied files will be moved back to avoid partially patched files lying around. - } - } - patch.remove(); - - // git add of all files. - QProcess git; - QStringList arguments; - arguments << "update-index" << "--remove" << filesForAdd; - GitRunner runner(git, arguments); - ReturnCodes rc = runner.start(GitRunner::WaitForStandardOutput); - if (rc != Ok) { - Logger::error() << "Adding files to the git index failed, aborting record\n"; - return rc; - } - - return Ok; // exiting scope will revert all files in the local filesystem. We use the index from here on. -} - diff --git a/Record.h b/Record.h deleted file mode 100644 index 5d1901e..0000000 --- a/Record.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#ifndef RECORD_H -#define RECORD_H - -#include "AbstractCommand.h" - -class ChangeSet; - -class Record : public AbstractCommand { -public: - Record(); - -protected: - virtual QString argumentDescription() const; - virtual ReturnCodes run(); - virtual QString commandDescription() const; - -private: - ReturnCodes addFilesPerAcceptance(const ChangeSet &changeSet, bool allChanges); -}; - -#endif diff --git a/Remove.cpp b/Remove.cpp deleted file mode 100644 index dabd697..0000000 --- a/Remove.cpp +++ /dev/null @@ -1,62 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * Copyright (C) 2002-2004 David Roundy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Remove.h" -#include "CommandLineParser.h" -#include "GitRunner.h" - -Remove::Remove() - : AbstractCommand("remove") -{ - CommandLineParser::setArgumentDefinition("rename " ); -} - -AbstractCommand::ReturnCodes Remove::run() -{ - if (! checkInRepository()) - return NotInRepo; - moveToRoot(); - // all we need to do is tell gits index that the file is deleted. - // easiest way to do that is to call update-index --remove --force-remove [file] - - if (dryRun()) - return Ok; - - QProcess git; - QStringList arguments; - arguments << "update-index" << "--remove" << "--force-remove"; - arguments += rebasedArguments(); - GitRunner runner(git, arguments); - return runner.start(GitRunner::WaitUntilFinished); -} - -QString Remove::argumentDescription() const -{ - return ""; -} - -QString Remove::commandDescription() const -{ - return "Remove should be called when you want to remove a file from your project,\n" - "but don't actually want to delete the file. Otherwise just delete the\n" - "file or directory, and vng will notice that it has been removed.\n" - "Be aware that the file WILL be deleted from any other copy of the\n" - "repository to which you later apply the patch.\n"; -} - diff --git a/Remove.h b/Remove.h deleted file mode 100644 index d1aca00..0000000 --- a/Remove.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef REMOVE_H -#define REMOVE_H - -#include "AbstractCommand.h" - -class Remove : public AbstractCommand { -public: - Remove(); - -protected: - virtual QString argumentDescription() const; - virtual ReturnCodes run(); - virtual QString commandDescription() const; -}; - -#endif diff --git a/Revert.cpp b/Revert.cpp deleted file mode 100644 index e910983..0000000 --- a/Revert.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "Revert.h" -#include "CommandLineParser.h" -#include "Interview.h" -#include "Logger.h" -#include "GitRunner.h" -#include "hunks/ChangeSet.h" -#include "hunks/HunksCursor.h" - -#include -#include - -static const CommandLineOption options[] = { - {"-a, --all", "answer yes to all patches"}, - {"-i, --interactive", "prompt user interactively"}, - CommandLineLastOption -}; - -Revert::Revert() - : AbstractCommand("revert") -{ - CommandLineParser::addOptionDefinitions(options); - CommandLineParser::setArgumentDefinition("revert [FILE or DIRECTORY]" ); -} - -AbstractCommand::ReturnCodes Revert::run() -{ - if (! checkInRepository()) - return NotInRepo; - moveToRoot(); - - CommandLineParser *args = CommandLineParser::instance(); - const bool all = m_config.contains("all") && !args->contains("interactive") || args->contains("all"); - - ChangeSet changeSet; - changeSet.fillFromCurrentChanges(rebasedArguments()); - - bool shouldDoRevert = changeSet.count() > 0; - if (!shouldDoRevert) - Logger::warn() << "There are no changes to revert!" << endl; - - if (shouldDoRevert && !all) { // then do interview - HunksCursor cursor(changeSet); - cursor.setConfiguration(m_config); - Interview interview(cursor, name()); - interview.setUsePager(shouldUsePager()); - if (! interview.start()) { - Logger::warn() << "Revert cancelled." << endl; - return Ok; - } - } - - if (shouldDoRevert && !all) { // check if there is anything selected - shouldDoRevert = changeSet.hasAcceptedChanges(); - if (! shouldDoRevert) - Logger::warn() << "If you don't want to revert after all, that's fine with me!" < - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef REVERT_H -#define REVERT_H - -#include "AbstractCommand.h" - -class Revert : public AbstractCommand { -public: - Revert(); - -protected: - virtual QString argumentDescription() const; - virtual ReturnCodes run(); - virtual QString commandDescription() const; - -private: - friend class UnRevert; - static QString patchFileName(); -}; - -#endif diff --git a/UnRecord.cpp b/UnRecord.cpp deleted file mode 100644 index a79b6b1..0000000 --- a/UnRecord.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * Copyright (C) 2003-2005 David Roundy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include "UnRecord.h" - -#include "CommandLineParser.h" -#include "Interview.h" -#include "GitRunner.h" -#include "Logger.h" -#include "commits/Commit.h" -#include "commits/CommitsCursor.h" - -#include - -static const CommandLineOption options[] = { - {"--from-match PATTERN", "select changes starting with a patch matching PATTERN"}, - {"--from-patch REGEXP", "select changes starting with a patch matching REGEXP"}, - //{"--from-tag REGEXP", "select changes starting with a tag matching REGEXP"}, - {"-n, --last NUMBER", "select the last NUMBER patches"}, - {"--match PATTERN", "select patches matching PATTERN"}, - {"-p, --patches REGEXP", "select patches matching REGEXP"}, - //{"-t REGEXP,--tags REGEXP", "select tags matching REGEXP"}, - CommandLineLastOption -}; - -UnRecord::UnRecord() - :AbstractCommand("unrecord") -{ - CommandLineParser::addOptionDefinitions(options); -} - -QString UnRecord::argumentDescription() const -{ - return QString(); -} - -QString UnRecord::commandDescription() const -{ - return "UnRecord does the opposite of record in that it makes the changes from\n" - "patches active changes again which you may record or revert later. The\n" - "working copy itself will not change.\n"; -} - -AbstractCommand::ReturnCodes UnRecord::run() -{ - if (! checkInRepository()) - return NotInRepo; - CommandLineParser *args = CommandLineParser::instance(); - - CommitsCursor cursor; - cursor.setUseMatcher(true); - if (args->contains("last")) { - int count = args->optionArgument("last").toInt(); - for (int i = 0; i < count && cursor.isValid(); i++) { - cursor.setResponse(true); - cursor.forward(); - } - } else { - Interview interview(cursor, name()); - interview.setUsePager(shouldUsePager()); - if (! interview.start()) { - Logger::warn() << "unrecord cancelled." << endl; - return Ok; - } - } - - Commit commit = cursor.head(); - Commit acceptedCommit; - int unrecordCount = 0; - bool oneAutoAcceptedPatch = false; - while (true) { - if (commit.acceptance() == Vng::Rejected) // can't use this one. - break; - else if (commit.acceptance() == Vng::Accepted) - acceptedCommit = commit; - if (commit.previousCommitsCount() == 0) // at first commit. - break; - if (commit.acceptance() == Vng::Undecided) { - if (acceptedCommit.isValid()) // already found a 'yes'. - break; - oneAutoAcceptedPatch = true; - } - commit = commit.previous()[0]; - if (unrecordCount >= cursor.oldestCommitAltered()) - break; - unrecordCount++; - } - - if (!acceptedCommit.isValid()) { - Logger::warn() << "Ok, if you don't want to unrecord anything, that's fine!\n"; - return Ok; - } - if (oneAutoAcceptedPatch) { - QString answer = Interview::ask(QString("Do you really want to unrecord %1 patches? ").arg(unrecordCount)); - if (! (answer.startsWith("y") || answer.startsWith("Y"))) - return Ok; - } - if (dryRun()) - return Ok; - - QProcess git; - QStringList arguments; - arguments << "update-ref" << "HEAD" << commit.commitTreeIsm(); - GitRunner runner(git, arguments); - AbstractCommand::ReturnCodes rc = runner.start(GitRunner::WaitUntilFinished); - if (rc != Ok) { - Logger::error() << "Failed to update the ref, sorry.\n"; - return rc; - } - // TODO find all files that were added in the commit(s) we just reverted. The files are there, but - // vng / git doesn't know about them. So we need to add them explicitly. - - return Ok; -} diff --git a/UnRecord.h b/UnRecord.h deleted file mode 100644 index 4a60368..0000000 --- a/UnRecord.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#ifndef UNRECORD_H -#define UNRECORD_H - -#include "AbstractCommand.h" - -class UnRecord : public AbstractCommand { -public: - UnRecord(); - -protected: - virtual QString argumentDescription() const; - virtual ReturnCodes run(); - virtual QString commandDescription() const; -}; - -#endif diff --git a/UnRevert.cpp b/UnRevert.cpp deleted file mode 100644 index d72be44..0000000 --- a/UnRevert.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * Copyright (C) 2003-2005 David Roundy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include "UnRevert.h" - -#include "CommandLineParser.h" -#include "Revert.h" -#include "Interview.h" -#include "GitRunner.h" -#include "Logger.h" -#include "hunks/ChangeSet.h" -#include "hunks/HunksCursor.h" - -#include - -static const CommandLineOption options[] = { - {"-a, --all", "answer yes to all patches"}, - {"-i, --interactive", "prompt user interactively"}, - CommandLineLastOption -}; - -UnRevert::UnRevert() - :AbstractCommand("unrevert") -{ - CommandLineParser::addOptionDefinitions(options); -} - -QString UnRevert::argumentDescription() const -{ - return QString(); -} - -QString UnRevert::commandDescription() const -{ - return "Unrevert is used to undo the results of a revert command. It is only\n" - "guaranteed to work properly if you haven't made any changes since the\n" - "revert was performed.\n"; -} - -AbstractCommand::ReturnCodes UnRevert::run() -{ - if (! checkInRepository()) - return NotInRepo; - moveToRoot(); - CommandLineParser *args = CommandLineParser::instance(); - const bool all = m_config.contains("all") && !args->contains("interactive") || args->contains("all"); - - ChangeSet changeSet; - QFile file(Revert::patchFileName()); - if (file.exists()) - changeSet.fillFromDiffFile(file); - - bool shouldDoRevert = changeSet.count() > 0; - if (!shouldDoRevert) - Logger::warn() << "There is nothing to unrevert!" << endl; - - if (shouldDoRevert && !all) { // then do interview - HunksCursor cursor(changeSet); - Interview interview(cursor, name()); - interview.setUsePager(shouldUsePager()); - if (! interview.start()) { - Logger::warn() << "Unrevert cancelled." << endl; - return Ok; - } - } - - if (! dryRun() && shouldDoRevert) { // we then write out the patch and call git apply with it - QFile patchFile(Revert::patchFileName() + ".tmp"); - changeSet.writeDiff(patchFile, all ? ChangeSet::AllHunks : ChangeSet::UserSelection); - QProcess git; - QStringList arguments; - arguments << "apply" << "--apply" << patchFile.fileName(); - GitRunner runner(git, arguments); - AbstractCommand::ReturnCodes rc = runner.start(GitRunner::WaitUntilFinished); - patchFile.remove(); - if (rc != 0) { - Logger::error() << "Unreverting failed on one or more patches"; - if (Logger::verbosity() < Logger::Chatty) - Logger::error() << ", rerun with --standard-verbosity to see the warnings"; - Logger::error() << endl; - Logger::warn() << git.readAllStandardError(); - Logger::warn().flush(); - return rc; - } - changeSet.writeDiff(file, all ? ChangeSet::AllHunks : ChangeSet::InvertedUserSelection); - if (file.size() == 0) - file.remove(); - } - Logger::warn() << "Finished unreverting." << endl; - return Ok; -} diff --git a/UnRevert.h b/UnRevert.h deleted file mode 100644 index ce3cd9e..0000000 --- a/UnRevert.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#ifndef UNREVERT_H -#define UNREVERT_H - -#include "AbstractCommand.h" - -class UnRevert : public AbstractCommand { -public: - UnRevert(); - -protected: - virtual QString argumentDescription() const; - virtual ReturnCodes run(); - virtual QString commandDescription() const; -}; - -#endif diff --git a/VngCommandLine.cpp b/VngCommandLine.cpp index abda7cd..7a762f5 100644 --- a/VngCommandLine.cpp +++ b/VngCommandLine.cpp @@ -21,18 +21,18 @@ #include "Logger.h" // commands -#include "Add.h" -#include "Branches.h" -#include "Changes.h" -#include "Initialize.h" -#include "Move.h" -#include "Push.h" -#include "Record.h" -#include "Remove.h" -#include "Revert.h" -#include "UnRevert.h" -#include "UnRecord.h" -#include "WhatsNew.h" +#include "commands/Add.h" +#include "commands/Branches.h" +#include "commands/Changes.h" +#include "commands/Initialize.h" +#include "commands/Move.h" +#include "commands/Push.h" +#include "commands/Record.h" +#include "commands/Remove.h" +#include "commands/Revert.h" +#include "commands/UnRevert.h" +#include "commands/UnRecord.h" +#include "commands/WhatsNew.h" #include diff --git a/WhatsNew.cpp b/WhatsNew.cpp deleted file mode 100644 index d1827eb..0000000 --- a/WhatsNew.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * Copyright (C) 2002-2004 David Roundy - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include "WhatsNew.h" -#include "hunks/ChangeSet.h" -#include "Logger.h" -#include "GitRunner.h" -#include "CommandLineParser.h" - -#include -#include - -static const CommandLineOption options[] = { - {"-s, --summary", "summarize changes"}, - {"--no-summary", "don't summarize changes"}, - {"-u, --unified", "output patch in a format similar to diff -u"}, - {"-l, --look-for-adds", "In addition to modifications, look for files that are not boring, and thus are potentially pending addition"}, - {"--dont-look-for-adds", "Don't look for any files or directories that could be added, and don't add them automatically"}, - //{"--boring", "don't skip boring files"}, - CommandLineLastOption -}; - -WhatsNew::WhatsNew() - : AbstractCommand("whatsnew") -{ - CommandLineParser::addOptionDefinitions(options); - CommandLineParser::setArgumentDefinition("whatsnew [FILE or DIRECTORY]" ); -} - -AbstractCommand::ReturnCodes WhatsNew::run() -{ - if (! checkInRepository()) - return NotInRepo; - moveToRoot(); - - CommandLineParser *args = CommandLineParser::instance(); - const bool lookForAdds = m_config.contains("look-for-adds") && !args->contains("dont-look-for-adds-summary") - || args->contains("look-for-adds"); - const bool printSummary = lookForAdds || m_config.contains("summary") && - !args->contains("no-summary") || args->contains("summary"); - const bool unified = m_config.contains("unified") || args->contains("unified"); - - if (shouldUsePager()) - Logger::startPager(); - ChangeSet changeSet; - changeSet.fillFromCurrentChanges(rebasedArguments()); - - QTextStream &out = Logger::standardOut(); - if (lookForAdds) { - QProcess git; - QStringList arguments; - arguments << "ls-files" << "-o" << "--directory" << "--no-empty-directory" << "--exclude-standard"; - - GitRunner runner(git, arguments); - ReturnCodes rc = runner.start(GitRunner::WaitForStandardOutput); - if (rc != Ok) - return rc; - - char buf[1024]; - while(true) { - qint64 lineLength = Vng::readLine(&git, buf, sizeof(buf)); - if (lineLength == -1) - break; - QString line = QString::fromUtf8(buf, lineLength); - out << "a " << line; - } - } - else if (changeSet.count() == 0) { - out << "No Changes!" << endl; - return Ok; - } - if (!printSummary && !unified) { - m_config.colorize(out); - out << "{\n"; - } - foreach(File file, changeSet.files()) { - file.outputWhatsChanged(out, m_config, printSummary, unified); - Logger::flushPager(); - } - if (!printSummary && !unified) { - m_config.colorize(out); - out << "}\n"; - m_config.normalColor(out); - } - - return AbstractCommand::Ok; -} - -QString WhatsNew::argumentDescription() const -{ - return QString("[FILE or DIRECTORY]"); -} - -QString WhatsNew::commandDescription() const -{ - return "whatsnew gives you a view of what changes you've made in your working\n" - "copy that haven't yet been recorded. The changes are displayed in\n" - "vng patch format.\n"; -} diff --git a/WhatsNew.h b/WhatsNew.h deleted file mode 100644 index d7dcd51..0000000 --- a/WhatsNew.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * This file is part of the vng project - * Copyright (C) 2008 Thomas Zander - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#ifndef WHATSNEW_H -#define WHATSNEW_H - -#include "AbstractCommand.h" - -class WhatsNew : public AbstractCommand { -public: - WhatsNew(); - -protected: - virtual ReturnCodes run(); - virtual QString argumentDescription() const; - virtual QString commandDescription() const; -}; - -#endif diff --git a/commands/Record.cpp b/commands/Record.cpp index 09b83c0..7589240 100644 --- a/commands/Record.cpp +++ b/commands/Record.cpp @@ -364,8 +364,11 @@ AbstractCommand::ReturnCodes Record::addFilesPerAcceptance(const ChangeSet &chan << removeFromIndex << ", someChangesAccepted: " << someEnabled << ", allAccepted: " << allEnabled << endl; if (file.fileName().isEmpty()) filesForAdd << file.oldFileName(); - else + else { filesForAdd << file.fileName(); + if (renamed) + filesForAdd << file.oldFileName(); + } if (addUnaltered) continue; // thats easy; whole file to add. @@ -430,10 +433,10 @@ AbstractCommand::ReturnCodes Record::addFilesPerAcceptance(const ChangeSet &chan } patch.remove(); - // git add of all files. + // git add of all files to get a nice list of changes into the index. QProcess git; QStringList arguments; - arguments << "update-index" << "--remove" << filesForAdd; + arguments << "update-index" << "--add" << "--remove" << filesForAdd; GitRunner runner(git, arguments); ReturnCodes rc = runner.start(GitRunner::WaitForStandardOutput); if (rc != Ok) { diff --git a/vng.pro b/vng.pro index a977c18..8e58ef4 100644 --- a/vng.pro +++ b/vng.pro @@ -14,18 +14,18 @@ SOURCES += \ InterviewCursor.cpp \ Configuration.cpp \ VngCommandLine.cpp \ - Add.cpp \ - Branches.cpp \ - Changes.cpp \ - Initialize.cpp \ - Move.cpp \ - Push.cpp \ - Record.cpp \ - Remove.cpp \ - Revert.cpp \ - UnRecord.cpp \ - UnRevert.cpp \ - WhatsNew.cpp \ + commands/Add.cpp \ + commands/Branches.cpp \ + commands/Changes.cpp \ + commands/Initialize.cpp \ + commands/Move.cpp \ + commands/Push.cpp \ + commands/Record.cpp \ + commands/Remove.cpp \ + commands/Revert.cpp \ + commands/UnRecord.cpp \ + commands/UnRevert.cpp \ + commands/WhatsNew.cpp \ hunks/Hunk.cpp \ hunks/File.cpp \ hunks/ChangeSet.cpp \ @@ -48,18 +48,18 @@ HEADERS += \ InterviewCursor.h \ Configuration.h \ VngCommandLine.h \ - Add.h \ - Branches.h \ - Changes.h \ - Initialize.h \ - Move.h \ - Push.h \ - Record.h \ - Remove.h \ - Revert.h \ - UnRecord.h \ - UnRevert.h \ - WhatsNew.h \ + commands/Add.h \ + commands/Branches.h \ + commands/Changes.h \ + commands/Initialize.h \ + commands/Move.h \ + commands/Push.h \ + commands/Record.h \ + commands/Remove.h \ + commands/Revert.h \ + commands/UnRecord.h \ + commands/UnRevert.h \ + commands/WhatsNew.h \ hunks/Hunk.h \ hunks/File.h \ hunks/ChangeSet.h \ -- 2.11.4.GIT