1

Many revisions back, a good file in my SVN repository was overwritten. Revision 10, let's say, contains the file samplefile.txt in its desired form; the current revision is 30.

I update my working copy with the revision 10 samplefile.txt:

$ svn update -r 10 samplefile.txt

I confirm that my working copy of the file has this old but desired content in it. Now, I want to commit this file to the repo, forming version 31.

$ svn commit -m "reverting file to 10" samplefile.txt

This never commits, however. Executing the command returns me to the terminal prompt without the usual SVN output that confirms the new revision, and the updated file does not appear in the repository.

How do I commit this content using SVN commands?

PiotrChernin
  • 441
  • 8
  • 18
  • Possible duplicate of [Better way to revert to a previous SVN revision of a file?](http://stackoverflow.com/questions/345997/better-way-to-revert-to-a-previous-svn-revision-of-a-file) – alroc Nov 28 '16 at 19:16
  • @ alroc Thanks, I couldn't find that! While my question is essentially the same as that asker's, I don't understand any of the answers, most if not all of which concern "reverse merging". The asker appears to agree that reverse merging is an unsatisfactory solution, even though they did accept an answer. @twm's answer here, on the other hand, is not found in any of the answers in your link, and it appears to be precisely what I'm looking for if it works (I'll test it tomorrow to make sure). – PiotrChernin Nov 28 '16 at 20:35
  • The reverse merge *is* the most correct solution, so you should take the time to understand how it works. See also bahrep's answer below, as he's linked to the relevant section of the manual. – alroc Nov 28 '16 at 21:00
  • @alroc I've read the linked section of the manual, I've read the linked SO question, I've read `svn help merge`, I've searched for more information, and I still don't understand the `merge` command in enough detail to evaluate it as a solution. I'll have to ask about it as a separate question before I can resolve this issue. – PiotrChernin Nov 29 '16 at 19:59
  • That's unfortunate. I've found the Subverison manual to be some of the best software documentation I've read. – alroc Nov 29 '16 at 20:08

3 Answers3

1

You should run the following command in your working copy:

svn merge ^/trunk . -c-10

And commit this change:

svn commit -m "Revert changes made in r10"

Read SVNBook | Undoing Changes.

bahrep
  • 29,961
  • 12
  • 103
  • 150
  • Thanks for the link! That's some of the worst documentation I've ever seen, though. I've read it twice, as well as other sources, and I still don't understand how the `merge` command is defined, much less what a reverse merge is. Thank you for responding, but without further explanation I can't accept this as an answer. – PiotrChernin Nov 29 '16 at 19:50
  • @PiotrChernin It's not a reference, it's a manual chapter. Have you checked http://svnbook.red-bean.com/en/1.8/svn.ref.svn.c.merge.html ? – bahrep Nov 29 '16 at 19:53
  • Any further explanation you receive about merging in this context is going to be based upon the documentation you've been linked to so there's not a much point to rewriting what's already been explained in detail in the manual. This is the correct answer, whether you understand it or not. – alroc Nov 29 '16 at 20:10
  • @alroc I'm thinking to start a new doc about svn from scratch anyway. It seems to me that SVNBook in its current form does not really help users. SVNBook suffers from wordiness. – bahrep Nov 29 '16 at 20:12
  • 1
    @bahrep has a bingo there. The information required to define the `merge` command is spread over two or three different sections, the bulk of which are potentially irrelevant scenarios and diversions about changesets and `mergeinfo` - which, while important to understanding how `merge` works under the hood, are not necessary to learn how to use the command generally. I've written up a streamlined explanation and will post it. – PiotrChernin Nov 30 '16 at 21:40
  • @PiotrChernin you could address the feedback to http://www.red-bean.com/mailman/listinfo/svnbook-dev – bahrep Nov 30 '16 at 21:43
0

How svn merge Works

The svn merge command is used in several different ways, but fundamentally it always does two things in sequence: 1) create a diff by comparing two sources, and 2) apply that diff to a target.

The two sources and the target are specified by command-line arguments, though in many cases one or more arguments can be omitted if merge can determine implicitly what they're supposed to be.

In general, then, the command-line invocation has the form

$ svn merge [create diff] [apply to target]

In more detail,

1) [create diff]

svn merge compares source A and source B to create a diff, which is the set of instructions required to transform source A into source B.

The sources can be any element of the fileset: a trunk or branch, a directory subtree, or an individual file. A source can be either an element of the working copy (in which case it's identified by its filepath) or an element of the repository proper (in which case it's identified by its repo URL). A source can refer to any revision of the repository; if a revision isn't specified, the most recent revision (HEAD) is typically assumed.

2) [apply to target]

Once the diff is created, merge will then apply that set of instructions to the target. The target must be an element of a working copy; the merge command is usually assumed to be executed from within this working copy.

Obviously, if the target is completely unrelated to the two sources used to create the diff, then you'll just get nonsense when the diff instructions are applied to it. The target must also be the same "type of thing" as the two sources; that is, if the diff compares two branches or branch/trunk, then the target should also be either a branch or trunk. If the two sources are files, then the target should be a file, and so on.

This is why merge commands must be constructed carefully. Don't sweat it too much, though: since the target must be an element of your working copy, merge can only affect the working copy, not the repo. As long as you don't commit without checking the result of the merge, it's easy enough to fix if you merge incorrectly.

Reverse merges

A "reverse merge" to revert a file is a form of cherry-pick merge, which takes two different revisions of a single element as its two sources. Thus, we specify only one source name on the command line, accompanied by -r or -c flags to say which two revisions will be the sources.

The -r flag and its argument specify a revision, either as an absolute number N or as a range N:M.

The -c flag specifies the change made by a revision. This is useful in some cases, but not in this one because the difference between the current file (rev 30) and the desired file (rev 10) spans many changes over 20 different revisions - I don't want to revert a single change, but as many as twenty!

In terms of my hypothetical samplefile.txt,

[create diff] = -r 10:30 <URL of repository>/path/to/samplefile.txt

produces the set of instructions that transforms samplefile.txt@10 to samplefile.txt@30. That's not what I want, though - I want the opposite, the set of instructions that takes the current samplefile.txt@30 back to samplefile.txt@10. This can be specified by reversing the rev numbers, i.e.

[create diff] = -r 30:10 <URL of repository>/path/to/samplefile.txt

This is what makes it a "reverse merge". (Note that the -r flag has nothing to do with the word "reverse".)

My target is the file samplefile.txt within my working copy, or

[apply to target] = WC_root/filepath/to/samplefile.txt

Since the diff is constructed to take samplefile.txt@30 -> samplefile.txt@10, the copy in my working copy must be the latest version (rev 30). This is important to check, because I'd previously updated the file to rev 10 in an intuitive but for some reason futile attempt to commit that content back to the repository as revision 31. So always be sure to update before executing a merge command.

Reverting a file using a reverse merge

Putting [create diff] and [apply to target] together, the command to revert samplefile.txt from its rev 30 content to its rev 10 content using a reverse merge is

$ svn update
$ svn merge -r 30:10 <URL of repository>/path/to/samplefile.txt WC_root/filepath/to/samplefile.txt

If everything checks out, and the current content of samplefile.txt is indeed that of revision 10, then I now commit to the repo:

$ svn commit -m "reverting file to rev 10" WC_root/filepath/to/samplefile.txt

to lock in the file reversion for the benefit of the other developers.

References:

The best general documentation I could find about how the merge command is defined is given in the SVN Book here: Merge Syntax

The manual sections linked by @bahrep give several examples of how you might use merge to accomplish different tasks. (I can't repeat the links here because that puts me over the 2-link limit.)

And of course there's svn help merge, which will be much clearer after reading those links (and, hopefully, this answer).

Many thanks to @alroc and @bahrep for helping me sort this out!

PiotrChernin
  • 441
  • 8
  • 18
-1

Try this:

svn update samplefile.txt
svn cat -r 10 samplefile.txt > samplefile.txt
svn commit -m "reverting file to 10" samplefile.txt
twm
  • 1,448
  • 11
  • 19
  • 1
    These steps will break the history such that it won't show that revision 10 was "pulled forward" to the current HEAD revision. – alroc Nov 28 '16 at 19:15
  • 1
    @alroc The commit comment indicates the origin of this file is revision 10. Beyond that, I don't see why it would matter. Would this break any critical function of SVN, or are you just worried about comprehensive documentation? – PiotrChernin Nov 28 '16 at 20:30
  • 1
    @PiotrChernin it will break `svn:mergeinfo` since no mergeinfo is going to be recorded. – bahrep Nov 28 '16 at 20:32
  • 1
    @bahrep I've used SVN for some time now, and this is the first time `svn:mergeinfo` has ever come up, so I suspect that must not be important to me. What day-to-day function of using an SVN repository will break if I do this? Isn't @twm's solution just like committing a file whose changes just happen to make it identical to a previous version of the file? I do that all the time, and I've had no problems so far. – PiotrChernin Nov 29 '16 at 18:18