Move Matcher to its own class+file CommitsMatcher
[vng.git] / Revert.cpp
blob0dc7ab03ea1d598687e5ffc6c43f14f5a91c55e9
1 /*
2 * This file is part of the vng project
3 * Copyright (C) 2008 Thomas Zander <tzander@trolltech.com>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "Revert.h"
20 #include "CommandLineParser.h"
21 #include "Interview.h"
22 #include "Logger.h"
23 #include "GitRunner.h"
24 #include "hunks/ChangeSet.h"
25 #include "hunks/HunksCursor.h"
27 #include <QProcess>
28 #include <QDebug>
30 static const CommandLineOption options[] = {
31 {"-a, --all", "answer yes to all patches"},
32 {"-i, --interactive", "prompt user interactively"},
33 CommandLineLastOption
36 Revert::Revert()
37 : AbstractCommand("revert")
39 CommandLineParser::addOptionDefinitions(options);
40 CommandLineParser::setArgumentDefinition("revert [FILE or DIRECTORY]" );
43 AbstractCommand::ReturnCodes Revert::run()
45 if (! checkInRepository())
46 return NotInRepo;
47 moveToRoot();
49 CommandLineParser *args = CommandLineParser::instance();
50 const bool all = m_config.contains("all") && !args->contains("interactive") || args->contains("all");
52 ChangeSet changeSet;
53 changeSet.fillFromCurrentChanges(rebasedArguments());
55 bool shouldDoRevert = changeSet.count() > 0;
56 if (!shouldDoRevert)
57 Logger::info() << "There are no changes to revert!" << endl;
59 if (shouldDoRevert && !all) { // then do interview
60 HunksCursor cursor(changeSet);
61 cursor.setConfiguration(m_config);
62 Interview interview(cursor, name());
63 interview.setUsePager(shouldUsePager());
64 if (! interview.start()) {
65 Logger::info() << "Revert cancelled." << endl;
66 return Ok;
70 if (shouldDoRevert && !all) { // check if there is anything selected
71 shouldDoRevert = changeSet.hasAcceptedChanges();
72 if (! shouldDoRevert)
73 Logger::info() << "If you don't want to revert after all, that's fine with me!" <<endl;
76 if (shouldDoRevert && !all) { // ask user confirmation
77 QString answer = Interview::ask("Do you really want to revert these changes? ");
78 if (! (answer.startsWith("y") || answer.startsWith("Y")))
79 return Ok;
82 if (! dryRun() && shouldDoRevert) { // we then write out the patch and call git apply with it
83 QFile outFile(patchFileName());
84 changeSet.writeDiff(outFile, all ? ChangeSet::AllHunks : ChangeSet::UserSelection);
86 QProcess git;
87 QStringList arguments;
88 arguments << "apply" << "--apply" << "--reverse" << outFile.fileName();
90 GitRunner runner(git, arguments);
91 AbstractCommand::ReturnCodes rc = runner.start(GitRunner::WaitUntilFinished);
92 if (rc != Ok) {
93 Logger::error() << "internal error; failed to patch, sorry\n";
94 outFile.remove();
95 return rc;
99 Logger::info() << "Finished reverting." << endl;
100 return Ok;
103 QString Revert::argumentDescription() const
105 return "[FILE or DIRECTORY]";
108 QString Revert::commandDescription() const
110 return "Revert is used to undo changes made to the working copy which have\n"
111 "not yet been recorded. You will be prompted for which changes you\n"
112 "wish to undo. The last revert can be undone safely using the unrevert\n"
113 "command if the working copy was not modified in the meantime.\n";
116 // static
117 QString Revert::patchFileName()
119 return QString::fromLatin1(".git/.vng-revert.diff");
123 TODO
124 make sure we can revert file-renames too
125 check how we handle binary patches (i.e. no dataloss)
126 figure out a way to auto-adjust the line numbers for unrevert.