187

I know that I can svn diff -r a:b repo to view the changes between the two specified revisions. What I'd like is a diff for every revision that changed the file. Is such a command available?

Gordon Wilson
  • 26,244
  • 11
  • 57
  • 60

9 Answers9

188

There's no built-in command for it, so I usually just do something like this:

#!/bin/bash

# history_of_file
#
# Outputs the full history of a given file as a sequence of
# logentry/diff pairs.  The first revision of the file is emitted as
# full text since there's not previous version to compare it to.

function history_of_file() {
    url=$1 # current url of file
    svn log -q $url | grep -E -e "^r[[:digit:]]+" -o | cut -c2- | sort -n | {

#       first revision as full text
        echo
        read r
        svn log -r$r $url@HEAD
        svn cat -r$r $url@HEAD
        echo

#       remaining revisions as differences to previous revision
        while read r
        do
            echo
            svn log -r$r $url@HEAD
            svn diff -c$r $url@HEAD
            echo
        done
    }
}

Then, you can call it with:

history_of_file $1
Daniel Gray
  • 1,697
  • 1
  • 21
  • 41
bendin
  • 9,424
  • 1
  • 39
  • 37
  • 36
    I've never seen that "piping into the braced block" trick before. Neat. –  Nov 13 '08 at 20:26
  • 6
    [Batch file version](http://stackoverflow.com/questions/5622367/generate-history-of-changes-on-a-file-in-svn/5721533#5721533) of this script, fwiw. – ladenedge Apr 19 '11 at 19:23
  • I added this to my .bashrc file. When I start-up I get `svn: '.' is not a working copy svn: Syntax error in revision argument '@HEAD' svn: Syntax error in revision argument '@HEAD'` – Francisc0 Apr 22 '11 at 15:23
  • 1
    @Francisco0: don't include the final line in your bashrc. it's not part of the function definition, it's a call to the function because the example as given is intended for use as a stand-alone script. – bendin Oct 22 '11 at 08:04
  • I'm not that familiar with the intricacies of grep, but on mingw, grep does not support the -o option. is there a workaround for this? – Chris Drappier Mar 29 '12 at 21:08
  • Remember that /bin/bash is almost always bogus. Using /usr/bin/env bash is better. Writing POSIX scripts and using /bin/sh is best. – Good Person Mar 14 '13 at 14:53
  • What does `@HEAD` do in this context? I don't see a different with or without it locally. – dimo414 Sep 24 '13 at 18:56
  • I like this solution, but I found a situation where -c doesn't work as expected, and -r $prev:$next would work better. If a file is renamed from a working copy that is not up-to-date, it will not exist in the intervening revisions (for some notion of exist that applies to -c). – Nick Russo Aug 05 '14 at 21:27
  • 29
    `svn log --diff [path_to_file]` works exactly like this! http://stackoverflow.com/a/24938573/3185510 – webster Jun 02 '15 at 06:00
  • rahul, make yours an answer. – ahnbizcad Mar 09 '16 at 23:09
  • I added the possibility to limit the output with: limit=${2:-50} svn log -q $url -l $limit but then I've seen the comment from webster! – Zioalex Feb 09 '17 at 11:45
155

Slightly different from what you described, but I think this might be what you actually need:

svn blame filename

It will print the file with each line prefixed by the time and author of the commit that last changed it.

ngn
  • 7,763
  • 6
  • 26
  • 35
106

If you want to see whole history of a file with code changes :

svn log --diff [path_to_file] > log.txt
emilie zawadzki
  • 2,035
  • 1
  • 18
  • 25
  • 3
    I don't know when the --diff option has been added but it works with svn 1.8.10, so no need of a bash script – Guillaume Gros Aug 22 '14 at 15:52
  • 1
    I think, svn 1.7.4 introduced the option `--diff` since it has tests for the option whereas 1.7.3 has none - `subversion/tests/cmdline/log_tests.py`. – valid Mar 31 '16 at 09:00
  • Just a small note: depending on the length of the history, this can take quite some time before the log.txt file is completely rendered (though it will be readable immediately). – Ivan Durst Sep 06 '16 at 19:43
  • 1
    How does one limit this to the most recent X revisions? – Enigma Apr 04 '19 at 17:50
  • 1
    @Enigma: with the `--limit ` option. Like so: `svn log --diff --limit 5 [path_to_file]` – Reid Feb 18 '20 at 22:33
37

You could use git-svn to import the repository into a Git repository, then use git log -p filename. This shows each log entry for the file followed by the corresponding diff.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • 28
    Install git, create a git repository, use a git command? The question was tagged and asked about Subversion. – Ken Gentle Nov 12 '08 at 04:00
  • 21
    I use git as a Subversion client with git-svn. This is how I would do the log+diff operation against a Subversion repository. Git has some really excellent tools for repository viewing, it's not such an outlandish idea. – Greg Hewgill Nov 12 '08 at 04:02
  • 10
    Above someone is (rightly) congratulated on writing a nice script - to provide functionality not present in SVN. Seeing that git is local unless you push, you could call this tooling, no need to get all upset about things. – Adam Tolley Dec 18 '12 at 18:38
  • It's also the only answer that allows you to use a GUI (of choice) to view the file's history. The other answers also have not explained how to limit to the last X revisions (possible at all?), which is easy in git. `git log X..Y -o filename` – TamaMcGlinn Oct 09 '19 at 09:27
21

Start with

svn log -q file | grep '^r' | cut -f1 -d' '

That will get you a list of revisions where the file changed, which you can then use to script repeated calls to svn diff.

  • 4
    or... keep going! ``svn log -q some_file.xxx | grep ^r | awk '{print $1}' | sed -e 's/^r//' | xargs -i svn diff -rHEAD:{} some_file.xxx > ~/file_history.txt`` nice little one-liner (awk does same as cut) – Kasapo May 10 '13 at 17:10
8

The oddly named "blame" command does this. If you use Tortoise, it gives you a "from revision" dialog, then a file listing with a line by line indicator of Revision number and author next to it.

If you right click on the revision info, you can bring up a "Show log" dialog that gives full checkin information, along with other files that were part of the checkin.

goosemanjack
  • 940
  • 9
  • 7
  • 1
    Thats very useful, but not what the OP was looking for, which is a full history of the file, not just the historical contributions of the current file. That full history is useful when looking back to figure out why certain code was removed or changed, and when. – Adam Tolley Dec 18 '12 at 18:41
  • On the contrary, the name is quite right. It tells you whom to blame for a particular (crappy/buggy/uncomprehendable) chunk of code. – ivan_pozdeev Jan 29 '13 at 17:32
  • Wouldn't it be good if the obvious name for the command were "credit" rather than "blame" ? :) – Nick May 17 '13 at 09:44
  • 1
    @Nick svn praise is an alias to svn blame, depending on how one feels. – Stephane Gosselin May 27 '13 at 15:09
  • @stefgosselin - Thanks for that note. I'm glad to know there's a choice! :) – Nick May 28 '13 at 08:23
3

Thanks, Bendin. I like your solution very much.

I changed it to work in reverse order, showing most recent changes first. Which is important with long standing code, maintained over several years. I usually pipe it into more.

svnhistory elements.py |more

I added -r to the sort. I removed spec. handling for 'first record'. It is it will error out on the last entry, as there is nothing to diff it with. Though I am living with it because I never get down that far.

#!/bin/bash                                                                    

# history_of_file                                                              
#                                                                              
# Bendin on Stack Overflow: http://stackoverflow.com/questions/282802          
#   Outputs the full history of a given file as a sequence of                  
#   logentry/diff pairs.  The first revision of the file is emitted as         
#   full text since there's not previous version to compare it to.             
#                                                                              
# Dlink                                                                        
#   Made to work in reverse order                                              

function history_of_file() {
    url=$1 # current url of file                                               
    svn log -q $url | grep -E -e "^r[[:digit:]]+" -o | cut -c2- | sort -nr | {
        while read r
    do
            echo
            svn log -r$r $url@HEAD
            svn diff -c$r $url@HEAD
            echo
    done
    }
}

history_of_file $1
dlink
  • 1,489
  • 17
  • 22
3

As far as I know there is no built in svn command to accomplish this. You would need to write a script to run several commands to build all the diffs. A simpler approach would be to use a GUI svn client if that is an option. Many of them such as the subversive plugin for Eclipse will list the history of a file as well as allow you to view the diff of each revision.

D-Rock
  • 2,636
  • 1
  • 21
  • 26
1

I've seen a bunch of partial answers while researching this topic. This is what worked for me and hope it helps others. This command will display output on the command line, showing the revision number, author, revision timestamp and changes made:

svn blame -v <filename>

To make your search easier, you can write the output to a file and grep for what you're looking for.

alamba
  • 107
  • 1
  • 13