Avoid accidental commit of certain changes to a file in Subversion
The problem
I just accidentally committed a change to a file that was only meant to help debug a problem. As a result, I rather messed up the current version of our software, because I accidentally disabled important functionality :-(.
Since this is not the first time this happened (and I'm not the only one it happened to), my question:
Is there a practical mechanism to prevent accidental commits of changes you don't want committed?
I'm thinking of changes where you already know you don't want to commit them when you make them (such as modifications to help debugging or testing).
My current approach:
Usually I just mark such changes with a // FIXME: DEBUG
, so they get listed and highlighted in Eclipse. However this is not enough, as I can still commit these files.
I'd like some mechanism that tells Subversion "do not commit this file in this state" - maybe a special comment or some file property (like "lock this file for commits"). Is there any such mechanism?
The only solution I can think of wou开发者_运维百科ld be to have a pre-commit hook that scans for special comments, but I'd like to avoid having to configure stuff server-side if I can help it.
You could add a pre-commit hook to subversion that checks for a specific subversion property, e.g. mycompany:dontcommit
.
You could then set this property on the local file, and the subversion server will reject the file if you ever try to commit it.
We have been using this system for some time, and believe me, it has save me a couple of times. ;)
This answer is specific to Visual Studio, but I strongly suspect something similar could be done for Eclipse.
In Visual Studio using C#, I do all my development and most testing while compiling in Debug mode. Debug mode compiles with the DEBUG flag defined. Then, whenever I write test code that would break something, I put this in next to it:
#if !DEBUG
#error DEBUG is not defined. Fix the above lines, which are for debugging only.
#endif
Then I make sure that before I do a release to a production environment, I switch from compiling in Debug mode to compiling in Release mode. Release mode doesn't define the DEBUG symbol, so an error is generated by the compiler.
This, of course, won't work if you are not in the habit of always releasing in Release mode. It also won't work if you don't remember to copy & paste that code whenever you break something. But really, any solution is going to have problems like that.
Note that with my solution, I still forget and commit broken code to the SVN repository. However, as long as everyone is following the release process, as soon as someone goes to build a release, they get a compile error and spot the problem.
1) A debugging infrastructure. If you have statements in there all the time but turned off, then it doesn't matter if you check them in. In fact, you want to check them in. When debugging, turn debug on. You could also make your temporary workarounds dependent on the debug flag. E.g. when you want to skip a section of code:
if {$debugflag < 50} {
doImportantFeature
} else {
doMyDummyTestThing
}
2) Make your build process more robust. A lot of companies do auto-builds and even auto-installs every night, but that seems wrong to me. Not the frequency so much as the auto-.
3) Use a distributed revision control system. That way you can commit debug stuff locally if you want/forget, but you'll be reviewing that all again when you submit it to the master repository.
One local solution is to manage your files using change sets.
This is working for our organization.
Each dev has a "local-do-not-commit" change set where we put our debugging changes.
We also have a "real" change set that we intend to commit.
It does require you move "unassigned" changes into the correct change set.
We are using Eclipse/Subversive. This allows you to commit a specific change set from within Eclipse.
If you are using the SVN command line, there are "changelist" options to do this.
Note: Subversive "change sets" are not the same as SVN "changelists". (Not sure why this is. But, it is annoying.)
Soemtimes, the best thing you could do is write a unit test that sets up the environment the way you want and allow you to test this scenario and then when you commit it will start testing this automatically and often.
I also like the other ideas of using a flag like if (debug) that you can turn on at run-time only when you need it.
But to answer your questions, here is a pre-commit script that works for this. IT looks through all the files you are committing and if the file contains the text "DoNotCommit" then it will give you an error. I am planning on putting a comment like this whenever I make a change that is just for testing. What is nice is that you can put this comment in any type of file and it will always catch it.
#!/bin/bash
function die {
>&2 echo $1
exit 6
}
REPOS="$1"
TXN="$2"
SVNLOOK=/usr/bin/svnlook
# Make sure that the log message contains some text.
#$SVNLOOK log -t "$TXN" "$REPOS" | \
# grep -q "[a-zA-Z0-9]" || die "Blank message not allowed"
# make sure the files do not contain DoNotCommit
# this runs svnlook changed which shows a list of adds, updates and deletes, for each file it calls svnlook cat to look at the contents
for file in `$SVNLOOK changed -t "$TXN" "$REPOS" | awk '{print $2}'`; do
# skip over file that ends in / because it is a directory
if [[ "$file" != */ ]]; then
$SVNLOOK cat -t "$TXN" "$REPOS" "$file" | grep -q -i "DoNotCommit" && die "Found text DoNotCommit in $file";
fi
done
# Exit on all errors.
set -e
# uncomment this to make it always fail at the end while testing changes to script
#>&2 echo failing at end
#exit 3
# All checks passed, so allow the commit.
exit 0
My solution is handy when you happen to make a lot of temporary code changes in your workspace but do not intend to commit everything at the end of the day when you leave. This is what I do everyday.
I created a custom annotation called @Tempcheckout in my project. This I annotate those classes that I change only for temporary purposes. After committing at the end of the day (which can be anywhere like 20-30 files), I have a Jenkins job that is triggered by the commit and this scans all the classes in the codebase for the annotation and mails me in case I happened to commit anything unintended. (or any package pattern using google-Reflections).
精彩评论