SVN版本控制工具的使用

技術(shù)交流QQ群:1027579432汇鞭,歡迎你的加入龄恋!

歡迎關(guān)注我的微信公眾號(hào):CurryCoder的程序人生

1.SVN中的基礎(chǔ)概念

  • repository:源代碼庫(kù)讹蘑,源代碼統(tǒng)一存放的地方
  • checkout:當(dāng)手上沒(méi)有源代碼時(shí),可以從源代碼庫(kù)中checkout一份
  • commit:當(dāng)你已經(jīng)修改了代碼,就需要commit到源代碼倉(cāng)庫(kù)
  • update:當(dāng)你已經(jīng)checkout了一份源代碼后矿微,update一下就可以和源代碼倉(cāng)庫(kù)上的源代碼同步,手上的代碼就會(huì)有最新的變更尚揣。
    日常使用流程:假設(shè)你已經(jīng)在幾天前checkout涌矢,update獲取最新的代碼->自己進(jìn)行修改并調(diào)試成功源代碼->commit(大家就可以看到你的修改)
  • 如果兩個(gè)程序員同時(shí)修改了同一個(gè)文件, SVN可以合并這兩個(gè)程序員的改動(dòng),實(shí)際上SVN管理源代碼是以行為單位的惑艇,即兩個(gè)程序員只要不是修改同一行程序蒿辙,SVN都會(huì)自動(dòng)合并兩種修改。如果是同一行滨巴,SVN 會(huì)提示文件 Conflict, 沖突,需要手動(dòng)確認(rèn)俺叭。

2.linux系統(tǒng)下安裝SVN

  • yum install subversion(Centos下安裝)
  • sudo apt-get install subversion(Ubuntu下安裝)
  • 查看SVN的版本:subversion --version
    cdl@cdl-Inspiron-5421:~$ svn --version
    svn恭取,版本 1.9.3 (r1718519)
    編譯于 Jul 26 2019,15:51:17 在 x86_64-pc-linux-gnu
    

3.SVN啟動(dòng)模式

  • 在服務(wù)端進(jìn)行SVN版本庫(kù)的相關(guān)配置熄守,手動(dòng)創(chuàng)建版本庫(kù)目錄:
    cdl@cdl-Inspiron-5421:~$ sudo mkdir /opt/svn
    [sudo] cdl 的密碼: 
    
  • 利用SVN命令創(chuàng)建版本庫(kù)
    svnadmin create /opt/svn/CurryCoder
    
  • 使用命令svnserve啟動(dòng)服務(wù)
    • -r:決定了版本庫(kù)的訪問(wèn)方式蜈垮;
    • --listen-port:指定svn監(jiān)聽端口,不加此參數(shù)裕照,默認(rèn)為3690
      svnserve -d -r 目錄 --listen-port 端口號(hào)
      
    • 單庫(kù)svnserve方式:一個(gè)svnserve只能為一個(gè)版本庫(kù)工作攒发;
      svnserve -d -r /opt/svn/CurryCoder
      
      • authz配置文件中對(duì)版本庫(kù)權(quán)限的配置為:
        [groups]
        admin=user1
        dev=user2
        [/]
        @admin=rw
        user2=r
        
      • 使用類似這樣的URL:svn://192.168.0.1/ 即可訪問(wèn)CurryCoder版本庫(kù)
    • 多庫(kù)svnserve方式:指定到版本的上級(jí)目錄,一個(gè)svnserve可以為多個(gè)版本庫(kù)工作晋南。
      svnserve -d -r /opt/svn
      
      • authz配置文件中對(duì)版本庫(kù)的配置:
        [groups]
        admin=user1
        dev=user2
        [CurryCoder:/]
        @admin=rw
        user2=r
        
        [CurryCoder01:/]
        @admin=rw
        user2=r
        
      • 使用類似這樣的URL:svn://192.168.0.1/CurryCoder 即可訪問(wèn)CurryCoder版本庫(kù)

3.創(chuàng)建版本庫(kù)

  • 使用svnadmin create 目錄進(jìn)行創(chuàng)建版本庫(kù)惠猿。
    cdl@cdl-Inspiron-5421:~$ sudo svnadmin create /opt/svn/CurryCoder01
    [sudo] cdl 的密碼: 
    cdl@cdl-Inspiron-5421:~$ ll /opt/svn/CurryCoder01/
    總用量 32
    drwxr-xr-x 6 root root 4096 5月  26 11:19 ./
    drwxr-xr-x 4 root root 4096 5月  26 11:19 ../
    drwxr-xr-x 2 root root 4096 5月  26 11:19 conf/
    drwxr-sr-x 6 root root 4096 5月  26 11:19 db/
    -r--r--r-- 1 root root    2 5月  26 11:19 format
    drwxr-xr-x 2 root root 4096 5月  26 11:19 hooks/
    drwxr-xr-x 2 root root 4096 5月  26 11:19 locks/
    -rw-r--r-- 1 root root  246 5月  26 11:19 README.txt
    
  • 進(jìn)入/opt/svn/CurryCoder01/conf目錄,修改默認(rèn)配置文件內(nèi)容负间,包括svnserve.conf偶妖、passwd、authz等信息政溃。
    • svn服務(wù)配置文件為版本庫(kù)目錄中的文件conf/svnserve.conf趾访,該文件僅由一個(gè)[general]配置字段組成:
      [general]
      anon-access = none     # 控制非授權(quán)用戶訪問(wèn)版本庫(kù)的權(quán)限
      auth-access = write    # 控制授權(quán)用戶訪問(wèn)版本庫(kù)的權(quán)限。
      password-db = /home/svn/passwd
      authz-db = /home/svn/authz  # 指定權(quán)限配置文件名董虱,通過(guò)該文件可以實(shí)現(xiàn)以路徑為基礎(chǔ)的訪問(wèn)控制扼鞋。除非指定絕對(duì)路徑,否則文件位置為相對(duì)conf目錄的相對(duì)路徑愤诱。 默認(rèn)值:authz
      realm = tiku  # 指定版本庫(kù)的認(rèn)證域云头,即在登錄時(shí)提示的認(rèn)證域名稱。
      
    • 用戶名口令文件passwd:用戶名口令文件由svnserve.conf的配置項(xiàng)password-db指定转锈,默認(rèn)為conf目錄中的passwd盘寡。該文件僅由一個(gè)[users]配置段組成:
      [users]  
      admin = admin  # <用戶名> = <口令>
      CurryCoder = 123456
      
    • 權(quán)限配置文件:權(quán)限配置文件由svnserve.conf的配置項(xiàng)authz-db指定,默認(rèn)為conf目錄中的authz撮慨。該配置文件由一個(gè)[groups]配置段和若干個(gè)版本庫(kù)路徑權(quán)限段組成:
      [groups]   # <用戶組> = <用戶列表>
      g_admin = admin,CurryCoder
      
      [admintools:/]  # [<版本庫(kù)名>:<路徑>] 
      @g_admin = rw
      * =
      
      [test:/home/CurryCoder]
      CurryCoder = rw
      * = r
      

4.checkout(克隆副本)操作

  • 通過(guò)url svn://192.168.0.1(具體的svn服務(wù)器地址)/CurryCoder01 --username=user01竿痰,如下所示:
    cdl@cdl-Inspiron-5421:~$ svn checkout svn://192.168.0.1/CurryCoder01 --username=user01
    A    CurryCoder01/trunk
    A    CurryCoder01/branches
    A    CurryCoder01/tags
    Checked out revision 1.
    
  • checkout成功后在當(dāng)前目錄下生成CurryCoder01副本目錄脆粥,如下所示:
    root@cdl-Inspiron-5421:/home/cdl#  ll CurryCoder01/
    total 24
    drwxr-xr-x 6 root root 4096 Jul 21 19:19 ./
    drwxr-xr-x 3 root root 4096 Jul 21 19:10 ../
    drwxr-xr-x 2 root root 4096 Jul 21 19:19 branches/
    drwxr-xr-x 4 root root 4096 Jul 21 19:19 .svn/
    drwxr-xr-x 2 root root 4096 Jul 21 19:19 tags/
    drwxr-xr-x 2 root root 4096 Jul 21 19:19 trunk/
    

5.解決版本沖突

  • 版本沖突的產(chǎn)生原因:假設(shè)A和B兩個(gè)程序員都在版本號(hào)為100時(shí),修改了HelloWorld.html文件影涉。程序員A在修改完成后提交HelloWorld.html文件到服務(wù)器变隔。此時(shí),提交成功后HelloWorld.html文件的版本號(hào)變?yōu)?01蟹倾。同時(shí)匣缘,B程序員在版本號(hào)為100的HelloWorld.html文件上修改。修改完成后鲜棠,提交到服務(wù)器時(shí)肌厨,由于不是在當(dāng)前最新的101版本上修改的,所以提交時(shí)會(huì)失敗豁陆。
  • 查看修改后的文件內(nèi)容:
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/trunk$# cat HelloWorld.html 
    HelloWorld! http://www.runoob.com/
    
  • 查看更改:
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/trunk$# svn diff
    Index: HelloWorld.html
    ===================================================================
    --- HelloWorld.html     (revision 5)
    +++ HelloWorld.html     (working copy)
    @@ -1,2 +1 @@
    -HelloWorld! http://www.runoob.com/
    +HelloWorld! http://www.runoob.com/!
    
  • user01提交會(huì)出現(xiàn)失敻贪帧:
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/trunk$# svn commit -m "change HelloWorld.html first"
    Sending        HelloWorld.html
    Transmitting file data .svn: E160028: Commit failed (details follow):
    svn: E160028: File '/trunk/HelloWorld.html' is out of date
    
  • 提交失敗的原因:HelloWorld.html已經(jīng)被user02修改并提交到了倉(cāng)庫(kù)。svn不會(huì)允許user01提交更改盒音,因?yàn)閡ser02已經(jīng)修改了倉(cāng)庫(kù)表鳍,所以u(píng)ser01的工作副本已經(jīng)失效。為了避免兩人的代碼被互相覆蓋祥诽,svn不允許進(jìn)行這樣的操作譬圣。所以u(píng)ser01在提交更改之前必須先更新工作副本。所以使用update命令雄坪,如下:
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/trunk$# svn update
    Updating '.':
    C    HelloWorld.html
    Updated to revision 6.
    Conflict discovered in file 'HelloWorld.html'.
    Select: (p) postpone, (df) show diff, (e) edit file, (m) merge,
            (mc) my side of conflict, (tc) their side of conflict,  # 輸入mc表示以本地文件為主厘熟,也可以使用其他選項(xiàng)對(duì)沖突文件進(jìn)行不同的操作。
            (s) show all options: mc
    Resolved conflicted state of 'HelloWorld.html'
    Summary of conflicts:
    Text conflicts: 0 remaining (and 1 already resolved)
    
  • 默認(rèn)是更新到最新的版本诸衔,也可以指定更新到哪個(gè)版本:
    svn update -r6
    
  • 工作副本已經(jīng)與倉(cāng)庫(kù)同步盯漂,可以進(jìn)行提交
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/trunk$# svn commit -m "change HelloWorld.html second"
    

6.SVN提交操作

  • 在版本庫(kù)中增加一個(gè)readme的說(shuō)明文件:
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/trunk$# cat readme
    this is SVN tutorial.
    
  • 查看工作副本的狀態(tài)
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/trunk$# svn status
    ?       readme  # ?說(shuō)明它還未加到版本控制中
    
  • 將文件readme加到版本控制笨农,等待提交到版本庫(kù)就缆。
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/trunk$# svn add readme
    A         readme
    
  • 查看工作副本的狀態(tài)
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/trunk$# svn status
    A       readme  # A意味著這個(gè)文件已經(jīng)被成功地添加到了版本控制中
    
  • 為了把readme存儲(chǔ)到版本庫(kù)中,使用commit -m加上注釋信息來(lái)提交:
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/trunk$# svn commit -m "SVN readme."
    Adding         readme
    Transmitting file data .
    Committed revision 8.
    svn commit -m "SVN readme."
    

7.SVN版本回退

  • 當(dāng)我們想放棄對(duì)文件的修改谒亦,可以使用 SVN revert 命令竭宰。svn revert操作將撤銷任何文件或目錄里的局部更改
  • 對(duì)文件readme文件進(jìn)行修改(readme文件還沒(méi)有被提交)份招,查看文件狀態(tài):
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/trunk$# svn status
    M         readme   # M表示readme文件已經(jīng)被修改
    
  • 但是切揭,發(fā)現(xiàn)修改readme文件出現(xiàn)錯(cuò)誤,要撤銷修改锁摔,通過(guò)svn revert命令將文件readme回退到未修改狀態(tài):
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/trunk$# svn revert readme
    Reverted 'readme'
    
  • revert操作不單單可以使單個(gè)文件恢復(fù)原狀廓旬, 而且可以使整個(gè)目錄恢復(fù)原狀⌒逞恢復(fù)目錄用-R命令:
    svn revert -R trunk
    
  • 如何恢復(fù)一個(gè)已經(jīng)提交的版本孕豹?為了消除一個(gè)舊版本涩盾,必須撤銷舊版本里的所有更改然后提交一個(gè)新版本。首先励背,找到倉(cāng)庫(kù)的當(dāng)前版本春霍,假設(shè)現(xiàn)在是版本22,我們要撤銷回之前的版本叶眉,比如版本21址儒。
    svn merge -r 22:21 readme
    

8.SVN查看歷史信息

  • svn log: 顯示svn的版本作者、日期衅疙、路徑等信息莲趣;
    • 如果只希望查看特定的某兩個(gè)版本之間的信息,可以使用:svn log -r 6:8
    • 如果只想查看某個(gè)文件的版本修改信息炼蛤,可以使用:svn log 文件路徑
    • 如果希望得到目錄的信息要加 -v
      如果希望顯示限定N條記錄的目錄信息:svn log -l N -v
  • svn diff: 顯示特定修改的行的詳細(xì)信息妖爷;
    • 如果用svn diff,不帶任何參數(shù)理朋,它將會(huì)比較你的工作文件與緩存在.svn的"原始"拷貝
    • 比較你工作拷貝和版本庫(kù)中版本號(hào)為3的文件rule.txt: svn diff -r rule.txt
    • 比較 svn 工作版本中版本號(hào)2和3的這個(gè)文件的變化:svn diff -r 2:3 rule.txt
  • svn cat:將特定版本的某個(gè)文件內(nèi)容顯示在屏幕上;
    • 如果只是希望檢查一個(gè)過(guò)去版本绿聘,不希望查看它們的區(qū)別: svn cat -r 版本號(hào) rule.txt
  • svn list:可以在不下載文件到本地目錄的情況下來(lái)察看目錄中的文件嗽上;

9.SVN分支

  • 應(yīng)用場(chǎng)景:當(dāng)有人希望開發(fā)過(guò)程分開成兩條不同的路線時(shí),此時(shí)使用分支熄攘。比如項(xiàng)目下有兩個(gè)小組兽愤,svn下有一個(gè)trunk版本。由于客戶需求突然變化挪圾,導(dǎo)致項(xiàng)目需要做較大改動(dòng)浅萧,此時(shí)項(xiàng)目組決定由小組1繼續(xù)完成原來(lái)正進(jìn)行到一半的工作(某個(gè)模塊),小組2進(jìn)行新需求的開發(fā)哲思。那么此時(shí)洼畅,我們就可以為小組2建立一個(gè)分支,分支其實(shí)就是trunk版(主干線)的一個(gè)copy版棚赔,不過(guò)分支也是具有版本控制功能的帝簇,而且是和主干線相互獨(dú)立的,當(dāng)然靠益,最后我們可以通過(guò)(合并)功能丧肴,將分支合并到trunk上來(lái),從而最后合并為一個(gè)項(xiàng)目胧后。
  • 本地副本中創(chuàng)建my_branch分支
    root@cdl-Inspiron-5421:~/svn/CurryCoder01# svn copy branches/my_branch
    
  • 查看狀態(tài)
    root@cdl-Inspiron-5421:~/svn/CurryCoder01# svn status
    A  +    branches/my_branch
    A  +    branches/my_branch/HelloWorld.html
    A  +    branches/my_branch/readme
    
  • 提交新增的分支到版本庫(kù)中:
    root@cdl-Inspiron-5421:~/svn/CurryCoder01# svn commit -m "add my_branch"
    Adding         branches/my_branch
    Replacing      branches/my_branch/HelloWorld.html
    Adding         branches/my_branch/readme
    
    Committed revision 9.
    
  • 切換到分支路徑并創(chuàng)建index.html文件
    root@cdl-Inspiron-5421:~/svn/CurryCoder01# cd branches/my_branch/
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/branches/my_branch# ls
    HelloWorld.html  index.html  readme
    
  • 將index.html加入版本控制芋浮,并提交到版本庫(kù)中:
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/branches/my_branch# svn status
    ?       index.html
    
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/branches/my_branch# svn add index.html
    A         index.html
    
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/branches/my_branch# svn commit -m "add index.html"
    Adding         index.html
    Transmitting file data .
    Committed revision 10.
    
  • 切換到trunk主分支,執(zhí)行svn update壳快,然后將my_branch分支合并到trunk主分支中
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/trunk# svn merge ../branches/my_branch/
    --- Merging r10 into '.':
    A    index.html
    --- Recording mergeinfo for merge of r10 into '.':
    G   .
    
  • 將合并好的trunk主分支提交到版本庫(kù)中
    root@cdl-Inspiron-5421:~/svn/CurryCoder01/trunk# svn commit -m "add index.html"
    Adding         index.html
    Transmitting file data .
    Committed revision 11.
    

10.SVN標(biāo)簽

  • 版本管理系統(tǒng)支持tag選項(xiàng)纸巷,通過(guò)使用tag的概念镇草,可以給某一個(gè)具體版本的代碼一個(gè)更加有意義的名字。
  • 在本地工作副本創(chuàng)建一個(gè)tag:
    root@cdl-Inspiron-5421:~/svn/CurryCoder01# svn copy trunk/ tags/v1.0
    A         tags/v1.0
    
  • 上面的代碼成功完成何暇,新的目錄將會(huì)被創(chuàng)建在tags目錄下:
    root@cdl-Inspiron-5421:~/svn/CurryCoder01# ls tags/
    v1.0
    root@cdl-Inspiron-5421:~/svn/CurryCoder01# ls tags/v1.0/
    HelloWorld.html  readme
    
  • 查看狀態(tài):
    root@cdl-Inspiron-5421:~/svn/CurryCoder01# svn status
    A  +    tags/v1.0
    
  • 提交tag內(nèi)容:
    root@cdl-Inspiron-5421:~/svn/CurryCoder01# svn commit -m "tags v1.0"
    Adding         tags/v1.0
    Transmitting file data ..
    Committed revision 14.
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末陶夜,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子裆站,更是在濱河造成了極大的恐慌条辟,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宏胯,死亡現(xiàn)場(chǎng)離奇詭異羽嫡,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)肩袍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門杭棵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人氛赐,你說(shuō)我怎么就攤上這事魂爪。” “怎么了艰管?”我有些...
    開封第一講書人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵滓侍,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我牲芋,道長(zhǎng)撩笆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任缸浦,我火速辦了婚禮夕冲,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘裂逐。我一直安慰自己歹鱼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開白布絮姆。 她就那樣靜靜地躺著醉冤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪篙悯。 梳的紋絲不亂的頭發(fā)上蚁阳,一...
    開封第一講書人閱讀 49,785評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音鸽照,去河邊找鬼螺捐。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的定血。 我是一名探鬼主播赔癌,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼澜沟!你這毒婦竟也來(lái)了灾票?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤茫虽,失蹤者是張志新(化名)和其女友劉穎刊苍,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體濒析,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡正什,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了号杏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片婴氮。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖盾致,靈堂內(nèi)的尸體忽然破棺而出主经,到底是詐尸還是另有隱情,我是刑警寧澤庭惜,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布旨怠,位于F島的核電站,受9級(jí)特大地震影響蜈块,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜迷扇,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一百揭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蜓席,春花似錦器一、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至雏胃,卻和暖如春请毛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瞭亮。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工方仿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓仙蚜,卻偏偏與公主長(zhǎng)得像此洲,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子委粉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348