Subversion Version Control. Using The Subversion Version Control System in Development Projects
5.3. Modifying and Committing Data
The meat of Subversion is its usefulness for tracking changes in files over time. That makes getting those changes into the system a very important part of the system. The primary tool that you will use to get data into the system is the commit command, svn commit. In general, the basic committing process will go something like this. $ svn update At revision 3215. $ svn status M light.c $ svn commit --message "Added a status variable." Sending light.c Transmitting file data . Committed revision 3216.
It's a good idea to run the svn update command first, so that you can get any changes that others have made to the repository and make sure they will be compatible with your change. If there are any other changes merged into your working copy when you run update, it's also a good idea to recompile and run a test suite if one is available, to ensure that everything still works as you expect. Subversion won't let you commit changes that will result in a merge conflict without first making you resolve those changes by hand. However, it doesn't have any context for your source, and will not in any way prevent changes that cause logical conflicts in the project. The only conflicts that it catches are instances where either two people edited the exact same lines of a file or two people edited the same binary file. It is also a good idea to run the svn status command before you commit, in order to get an idea of what it is that you'll be committing. That way, you help avoid getting a stray change in an unrelated file mixed in with your commit just because you forgot that you made the change. You can also make use of the svn diff command if you don't remember exactly what changes you made to individual files. To find out more information about svn status and svn diff, take a look at Section 5.4, "Getting Information About the Repository." As soon as you feel that you have a good understanding of what you are committing, it's time to perform the actual commit. In the preceding example, the command was run with no path and with a log message on the command line. When svn commit is run with no path telling it what to commit, it recursively commits all modified files in the current directory. Recursion can be turned off with --no-recursion if you need to commit a directory without committing its contents. When the commit command runs, it sends the local modifications to the files being committed to the remote repository. Only the differences are sent, so no bandwidth is wasted by sending redundant information. If no paths are specified by svn commit, it recursively commits all of the modified files in the current directory. If you don't want to commit all of the locally modified files, you can instead specify one or more files on the command line, and it will instead commit only those files. Or, you can specify directories on the command line, and Subversion will commit that directory and any changed files or directories it contains (unless you specifically turned off recursion). In addition to files to commit, svn commit also requires a log message to associate with the commit. The log message can be supplied on the command line by giving the --message (-m) option. If you supply the log this way, the log message should follow the --message (separated by a space), and be enclosed in quotes. $ svn commit -m "A little inline log message. How cute." Entering log messages on the command line can quickly become unwieldyespecially if they are long messages. To make entering long messages easier, you can leave off the --message option, and Subversion will automatically open an editor for you to enter a log message (as you can see in Figure 5.1). Subversion will then block until you quit the editor. If you have entered a log message and saved the file, Subversion will use the contents of that file as the log message for the commit. If you quit without changing the file, Subversion will instead ask you if you want to use a blank log message or abort the commit. This abort capability can come in handy when you realize that you were a little too quick to commit and either forgot to add a file to the those that are being committed, or are accidentally committing too many files. As an aid to helping you figure out what is being committed Subversion will put a section in the commit log file, when it opens the editor, that tells you exactly which files are being committed. That section will then be removed from the file before Subversion sets the commit log. Figure 5.1. Adding a log with a text editor.
A third method for entering log messages is to put them in a file and have Subversion read the file by using the option --file (-F)which takes a single argument specifying the file to read. When specifying a file for the log message though, Subversion will not, by default, allow you to use a file that is already under version control. If you do want to use a file that is under version control for your log message, you can override Subversion's limitation by passing --force-log to svn commit. 5.3.1. Adding New Files
New files added to the working copy need to be explicitly put under version control before they can be committed to the repository. Adding files is a two-step process. The first step is to schedule the file for addition, with the svn add command, which adds the file in the working copy, but doesn't contact the remote repository. The actual transfer of data to the repository doesn't occur until svn commit is run on the newly added file. If you decide not to add the file, before performing the commit, you can unschedule the file by running svn revert on it. $ svn add memory.* A memory.c A memory.o $ svn revert memory.o Reverted 'memory.o' $ svn status A memory.c ? memory.o $ svn commit --message "Added a file for managing memory." Adding memory.c Transmitting file data . Committed revision 1492. If svn add is called on a directory, it will recursively add all of the files in that directory, unless you call svn add with --non-recursive. $ svn add my_project A my_project A my_project/file_1.c A my_project/file_2.c $ svn add --non-recursive my_project A my_project
5.3.2. Removing Files
Occasionally, it is also necessary to remove files from the repository. Subversion handles this with the svn delete command, which removes a file from the local working copy and schedules it to be removed in the next revision of the repository when a commit is executed. When files are removed though, Subversion only removes them for subsequent revisions. The file will always be there in any past revisions.[2] [2] There is talk of a feature that would allow files to be retroactively removed, but as of this writing, no such feature exists. $ svn delete image.cpp D image.cpp $ ls image.cpp ls: image.cpp: No such file or directory $ svn status D image.cpp
As you can see, when svn delete was run, it did indeed delete the file image.cpp and an svn status shows that the file is scheduled to be deleted. As with svn add, if you later decide (before committing the deletion to the repository) that you really didn't want to delete the file, you can undelete it by running svn revert with the name of the file you want to get back. After you have committed a remove operation, you will have to use the command svn copy to get the file back into the HEAD revision. When performing an svn delete, you need to be cautious about local modifications that have not yet been committed. After a file has been removed, you can use revert to get back a pristine version of the file from the last update, but all uncommitted local modifications will be irretrievably lost. Fortunately, Subversion has a safeguard that will prevent you from doing this accidentally. If svn delete detects local changes, it will fail, with a message telling you that you need to explicitly force it to delete the file, which you can do with the --force option. $ svn delete mobius.pl svn: Use --force to override this restriction svn: 'movius.pl' has local modifications $ svn delete --force mobius.pl D mobius.pl
In addition to removing files via your working copy, it is also possible with Subversion to directly remove files in a repository by specifying the file with a URL. Unlike removing a file in your working copy, when you use a URL you do not need to perform an explicit commit to cause the deletion to take effect in the repository. Instead, svn rm performs an implicit commit automatically when it is operating on a URL. Just as it does when you do an svn commit, the implicitly triggered commit will bring up an editor to allow you to input a log message, if you haven't supplied one with a --message. $ svn delete --message "Removed build.xml" http://svn.example.com/repos/trunk/build.xml Committed revision 702. 5.3.3. Moving Things Around
One of the biggest strengths of Subversion is the ease and efficiency with which it allows you to copy and move files under revision control. With relative impunity, you can shuffle files around with few worries about running into difficulties down the road as a result. All repository-side copies and moves are also done without physically copying the data. Instead, the repository simply makes a note of the new file's location and makes it point back to the original data. Then, if a copy is changed down the road, Subversion stores those changes along with the entry for the copy. In that way, a copy can "branch" from the original file, retaining the original file's history (precopy), but continuing on its own path from that point on. To help illustrate how this works, Figure 5.2 shows an example of the different versions of a file that has been copied. As you can see, the copy, Bar.cpp has diverged from the original, but continues to maintain a linkage back to its history at the time it was created. Figure 5.2. Two copies of a file, stored in the repository.
The two primary commands that you will use for dealing with moving and copying files are (shockingly) svn move and svn copy, which can be shortened to svn mv and svn cp, respectively. For the most part, both commands work the sameexcept for the obvious difference. Like the svn delete command, they operate immediately on a working copy, but only schedule the operation to be sent to the repository on the next commit. Similarly, if you give a repository URL instead of a working copy path, the operations will be performed immediately on the repository with an implicit commit. Be careful though. When you are working within a working copy, you should always make sure that you use the Subversion copy and move commands for any versioned files, instead of the operating system equivalents. If you copy or move a file using a non- Subversion command, Subversion will not be aware of the change, and will continue to expect to find the file at its old location. The copy or moved version will be unversioned, and Subversion may complain that it can't find the old copy (or it might just quietly put it back during an update). $ svn copy foo.s bar.s A bar.s $ svn move foo.s foo.s.old A foo.s.old D foo.s $ svn status A + foo.s.old D foo.s A + bar.s
You may have noticed, after the copy and move in the preceding example, the status output has a new addition. Instead of just saying that foo.s.old and bar.s are scheduled to be added, it also puts a + in the fourth column of the output. This plus sign, which is always located in the fourth column of a status line, indicates that a file being added already has history associated with it, which will of course be carried over to the copied file. You'll also notice that the svn move command shows the old file as deleted and the new file as added. In fact, svn move is identical to running svn copy, followed by an svn remove on the original file. This is due to the process that Subversion uses internally when moving versioned files around. When a file is copied, Subversion creates the new file and points it back to the original file that it came from. That way, the file's history is preserved in the copy without any extra space requirements. Similarly, when a file is moved, Subversion does the same thing, but then removes the original file from the new revision. Hence, the result is identical to running svn copy followed by svn remove. Using copy to Undelete Files
The svn copy command allows the source of a copy to come not only from the current revisions of either a working copy or the repository, but also from different revisions. This can be a handy way of "undeleting" a file that accidentally (or otherwise) was deleted in a previous revision. Revisions are entered just as they are with any other command that takes a revision, by using the command option --revision. [View full width] $ svn copy --revision 921 http://example.com/repos/html/index.html http://example.com
|