diff --git a/src/bin/pg_rewind/RewindTest.pm b/src/bin/pg_rewind/RewindTest.pm
index 25f243b49e1ee3b2714a37eb66adb9a9a89c6c4d..b66ff0dc2ad5a07102b700af65005c6bbd93e983 100644
--- a/src/bin/pg_rewind/RewindTest.pm
+++ b/src/bin/pg_rewind/RewindTest.pm
@@ -13,16 +13,18 @@ package RewindTest;
 #
 # 2. setup_cluster - creates a PostgreSQL cluster that runs as the master
 #
-# 3. create_standby - runs pg_basebackup to initialize a standby server, and
+# 3. start_master - starts the master server
+#
+# 4. create_standby - runs pg_basebackup to initialize a standby server, and
 #    sets it up to follow the master.
 #
-# 4. promote_standby - runs "pg_ctl promote" to promote the standby server.
+# 5. promote_standby - runs "pg_ctl promote" to promote the standby server.
 # The old master keeps running.
 #
-# 5. run_pg_rewind - stops the old master (if it's still running) and runs
+# 6. run_pg_rewind - stops the old master (if it's still running) and runs
 # pg_rewind to synchronize it with the now-promoted standby server.
 #
-# 6. clean_rewind_test - stops both servers used in the test, if they're
+# 7. clean_rewind_test - stops both servers used in the test, if they're
 # still running.
 #
 # The test script can use the helper functions master_psql and standby_psql
@@ -56,6 +58,7 @@ our @EXPORT = qw(
 
   init_rewind_test
   setup_cluster
+  start_master
   create_standby
   promote_standby
   run_pg_rewind
@@ -182,7 +185,10 @@ max_connections = 10
 
 	# Accept replication connections on master
 	configure_hba_for_replication $test_master_datadir;
+}
 
+sub start_master
+{
 	system_or_bail('pg_ctl' , '-w',
 				   '-D' , $test_master_datadir,
 				   '-l',  "$log_path/master.log",
diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
index 05eff68185edd6ee118a7642dda1e14805d40dbb..fb26d093160a957a6842741d4b0db96a7a0f4445 100644
--- a/src/bin/pg_rewind/filemap.c
+++ b/src/bin/pg_rewind/filemap.c
@@ -78,6 +78,14 @@ process_source_file(const char *path, file_type_t type, size_t newsize,
 		strcmp(path, "postmaster.opts") == 0)
 		return;
 
+	/*
+	 * Pretend that pg_xlog is a directory, even if it's really a symlink.
+	 * We don't want to mess with the symlink itself, nor complain if it's a
+	 * symlink in source but not in target or vice versa.
+	 */
+	if (strcmp(path, "pg_xlog") == 0 && type == FILE_TYPE_SYMLINK)
+		type = FILE_TYPE_DIRECTORY;
+
 	/*
 	 * Skip temporary files, .../pgsql_tmp/... and .../pgsql_tmp.* in source.
 	 * This has the effect that all temporary files in the destination will be
@@ -112,7 +120,7 @@ process_source_file(const char *path, file_type_t type, size_t newsize,
 	switch (type)
 	{
 		case FILE_TYPE_DIRECTORY:
-			if (exists && !S_ISDIR(statbuf.st_mode))
+			if (exists && !S_ISDIR(statbuf.st_mode) && strcmp(path, "pg_xlog") != 0)
 			{
 				/* it's a directory in source, but not in target. Strange.. */
 				pg_fatal("\"%s\" is not a directory\n", localpath);
@@ -285,6 +293,12 @@ process_target_file(const char *path, file_type_t type, size_t oldsize,
 		strcmp(path, "postmaster.opts") == 0)
 		return;
 
+	/*
+	 * Like in process_source_file, pretend that xlog is always a  directory.
+	 */
+	if (strcmp(path, "pg_xlog") == 0 && type == FILE_TYPE_SYMLINK)
+		type = FILE_TYPE_DIRECTORY;
+
 	key.path = (char *) path;
 	key_ptr = &key;
 	exists = (bsearch(&key_ptr, map->array, map->narray, sizeof(file_entry_t *),
diff --git a/src/bin/pg_rewind/t/001_basic.pl b/src/bin/pg_rewind/t/001_basic.pl
index be7d887bb7c9723ca56b32fadc7522c7a62ee0e9..1764b17c907a1c6591b0f2776ac4cd5518cdf9f7 100644
--- a/src/bin/pg_rewind/t/001_basic.pl
+++ b/src/bin/pg_rewind/t/001_basic.pl
@@ -10,6 +10,7 @@ sub run_test
 	my $test_mode = shift;
 
 	RewindTest::setup_cluster();
+	RewindTest::start_master();
 
 	# Create a test table and insert a row in master.
 	master_psql("CREATE TABLE tbl1 (d text)");
diff --git a/src/bin/pg_rewind/t/002_databases.pl b/src/bin/pg_rewind/t/002_databases.pl
index b0b007a763ad20448aa1c28d7f22e0e8c367c4da..f10899d44017f3578a3094af3f6edcf325222824 100644
--- a/src/bin/pg_rewind/t/002_databases.pl
+++ b/src/bin/pg_rewind/t/002_databases.pl
@@ -10,6 +10,7 @@ sub run_test
 	my $test_mode = shift;
 
 	RewindTest::setup_cluster();
+	RewindTest::start_master();
 
 	# Create a database in master.
 	master_psql('CREATE DATABASE inmaster');
diff --git a/src/bin/pg_rewind/t/003_extrafiles.pl b/src/bin/pg_rewind/t/003_extrafiles.pl
index 0cd0ac4d5677bcde1c3384bfc15dbbd83ae81fe2..d317f53186bf6362192f40febdd9be90babca104 100644
--- a/src/bin/pg_rewind/t/003_extrafiles.pl
+++ b/src/bin/pg_rewind/t/003_extrafiles.pl
@@ -15,6 +15,7 @@ sub run_test
 	my $test_mode = shift;
 
 	RewindTest::setup_cluster();
+	RewindTest::start_master();
 
 	my $test_master_datadir = $RewindTest::test_master_datadir;
 
diff --git a/src/bin/pg_rewind/t/004_pg_xlog_symlink.pl b/src/bin/pg_rewind/t/004_pg_xlog_symlink.pl
new file mode 100644
index 0000000000000000000000000000000000000000..0830b5a330a72f835b8fad0c7d06c68d868c9bcc
--- /dev/null
+++ b/src/bin/pg_rewind/t/004_pg_xlog_symlink.pl
@@ -0,0 +1,79 @@
+#
+# Test pg_rewind when the target's pg_xlog directory is a symlink.
+#
+use strict;
+use warnings;
+use File::Copy;
+use File::Path qw(remove_tree);
+use TestLib;
+use Test::More;
+if ($windows_os)
+{
+	plan skip_all => 'symlinks not supported on Windows';
+	exit;
+}
+else
+{
+	plan tests => 4;
+}
+
+use RewindTest;
+
+sub run_test
+{
+	my $test_mode = shift;
+
+	my $master_xlogdir = "$tmp_check/xlog_master";
+
+	remove_tree($master_xlogdir);
+	RewindTest::setup_cluster();
+
+	# turn pg_xlog into a symlink
+	print("moving $test_master_datadir/pg_xlog to $master_xlogdir\n");
+	move("$test_master_datadir/pg_xlog", $master_xlogdir) or die;
+	symlink($master_xlogdir, "$test_master_datadir/pg_xlog") or die;
+
+	RewindTest::start_master();
+
+	# Create a test table and insert a row in master.
+	master_psql("CREATE TABLE tbl1 (d text)");
+	master_psql("INSERT INTO tbl1 VALUES ('in master')");
+
+	master_psql("CHECKPOINT");
+
+	RewindTest::create_standby();
+
+	# Insert additional data on master that will be replicated to standby
+	master_psql("INSERT INTO tbl1 values ('in master, before promotion')");
+
+	master_psql('CHECKPOINT');
+
+	RewindTest::promote_standby();
+
+	# Insert a row in the old master. This causes the master and standby
+	# to have "diverged", it's no longer possible to just apply the
+	# standy's logs over master directory - you need to rewind.
+	master_psql("INSERT INTO tbl1 VALUES ('in master, after promotion')");
+
+	# Also insert a new row in the standby, which won't be present in the
+	# old master.
+	standby_psql("INSERT INTO tbl1 VALUES ('in standby, after promotion')");
+
+	RewindTest::run_pg_rewind($test_mode);
+
+	check_query(
+		'SELECT * FROM tbl1',
+		qq(in master
+in master, before promotion
+in standby, after promotion
+),
+		'table content');
+
+	RewindTest::clean_rewind_test();
+}
+
+# Run the test in both modes
+run_test('local');
+run_test('remote');
+
+exit(0);