Git

Git 簡介

Git是目前世界上最先進的分布式版本控制系統,沒有之一。


勤用 git status 查看狀態和提示,準沒錯的。

廖雪峰 Git 教程


集中式 VS 分布式

CVS及SVN都是集中式的版本控制系統,而Git是分布式版本控制系統,集中式和分布式版本控制系統有什么區別呢?

先說集中式版本控制系統,版本庫是集中存放在中央服務器的,而干活的時候,用的都是自己的電腦,所以要先從中央服務器取得最新的版本,然后開始干活,干完活了,再把自己的活推送給中央服務器。中央服務器就好比是一個圖書館,你要改一本書,必須先從圖書館借出來,然后回到家自己改,改完了,再放回圖書館。

集中式版本控制系統

集中式版本控制系統最大的毛病就是必須聯網才能工作,如果在局域網內還好,帶寬夠大,速度夠快,可如果在互聯網上,遇到網速慢的話,可能提交一個10M的文件就需要5分鐘,這還不得把人給憋死啊。

那分布式版本控制系統與集中式版本控制系統有何不同呢?首先,分布式版本控制系統根本沒有“中央服務器”,每個人的電腦上都是一個完整的版本庫,這樣,你工作的時候,就不需要聯網了,因為版本庫就在你自己的電腦上。既然每個人電腦上都有一個完整的版本庫,那多個人如何協作呢?比方說你在自己電腦上改了文件A,你的同事也在他的電腦上改了文件A,這時,你們倆之間只需把各自的修改推送給對方,就可以互相看到對方的修改了。

說明

首先這里再明確一下,所有的版本控制系統,其實只能跟蹤文本文件的改動,比如TXT文件,網頁,所有的程序代碼等等,Git也不例外。版本控制系統可以告訴你每次的改動,比如在第5行加了一個單詞“Linux”,在第8行刪了一個單詞“Windows”。而圖片、視頻這些二進制文件,雖然也能由版本控制系統管理,但沒法跟蹤文件的變化,只能把二進制文件每次改動串起來,也就是只知道圖片從100KB改成了120KB,但到底改了啥,版本控制系統不知道,也沒法知道。

不幸的是,Microsoft的Word格式是二進制格式,因此,版本控制系統是沒法跟蹤Word文件的改動的,前面我們舉的例子只是為了演示,如果要真正使用版本控制系統,就要以純文本方式編寫文件。

因為文本是有編碼的,比如中文有常用的GBK編碼,日文有Shift_JIS編碼,如果沒有歷史遺留問題,強烈建議使用標準的UTF-8編碼,所有語言使用同一種編碼,既沒有沖突,又被所有平臺所支持。

使用Windows的童鞋要特別注意:
千萬不要使用Windows自帶的記事本編輯任何文本文件。原因是Microsoft開發記事本的團隊使用了一個非常弱智的行為來保存UTF-8編碼的文件,他們自作聰明地在每個文件開頭添加了0xefbbbf(十六進制)的字符,你會遇到很多不可思議的問題,比如,網頁第一行可能會顯示一個“?”,明明正確的程序一編譯就報語法錯誤,等等,都是由記事本的弱智行為帶來的。建議你下載 Notepad++ 代替記事本,不但功能強大,而且免費!記得把Notepad++的默認編碼設置為UTF-8 without BOM 即可:


Unix的哲學是——沒有消息就是好消息。

廢話說完了,下面開始命令

  • git init:將一個目錄或文件夾初始化成 Git 可以管理的倉庫( repository )
  • git add readme.txt:把 readme.txt 文件的修改添加到暫存區
  • git add .:將當前目錄下所有文件添加到暫存區;
  • git commit -m 'the commit info':將暫存區中的修改提交倉庫
  • git status:查看倉庫當前狀態;
  • git diff readme.txt:查看文件具體不同;
  • git log [--pretty=oneline]:查看提交歷史
  • git reset --hard HEAD^:回到上一個版本;
  • git reset --hard HEAD~n:回到上 n 個版本;
  • git reset --hard commit_id:回到commit_id對應的版本;
  • git reflog:查看命令歷史——包括每一次的commit_id!!這樣就可以任意穿越!!
  • git checkout -- readme.txt將 工作區中的修改 恢復到最近一次addcommit的狀態,即若add后又作了修改,就恢復到add時的狀態;若commit后作了修改,就恢復到commit時的狀態;(注意這里--是單獨在中間的,沒有和readme.txt連起來!)
  • git reset HEAD readme.txt將 暫存區中readme.txt的修改 撤銷(unstage)掉,重新放回工作區;
  • git rm a.txt:刪除a.txt并將修改添加到暫存區
  • git remote add origin https://github.com/xiaogmail/learnit.git 將本地倉庫與遠程倉庫關聯起來;
  • git push -u origin master:將本地倉庫推送到遠程倉庫;
    • 由于遠程庫是空的,我們第一次推送 master 分支時,加上了-u 參數,Git不但會把本地的 master 分支內容推送的遠程新的 master 分支,還會把本地的 master 分支和遠程的 master 分支關聯起來,在以后的推送或者拉取時就可以簡化命令,git push搞定。

  • git branch:查看分支;
  • git branch <name>:創建分支;
  • git checkout <name>:切換分支;
  • git checkout -b <name>:創建并切換分支;
  • git branch -d <name>:刪除分支;
  • git merge <name>:合并某個分支到當前分支;
  • git merge --abort:終止合并(在遇到沖突要你手動合并時);
  • git log --graph --pretty=oneline --abbrev-commit:查看分支圖;
  • git merge --no-ff dev -m 'master merge dev with --no-ff'強制非快進模式,這才是正確使用方式。不要默認的 Fast-forward。
  • git stash:保存和隱藏當前工作現場;
  • git stash list:查看隱藏的工作現場;
  • git stash apply:恢復工作現場;
  • git stash drop:刪除隱藏的工作現場;
  • git stash pop:恢復并刪除;
  • git remote:查看遠程倉庫信息;
  • git remote -v:查看更詳細的信息(url 地址);
  • git push origin branch-name:從本地推送分支;
  • git checkout -b branch-name origin/branch-name在本地創建和遠程分支對應的分支;
  • git branch --set-upstream-to=origin/branch-name:建立本地分支和遠程分支的關聯;
  • git pull:從遠程分支抓取。如果有沖突,先解決沖突;
  • git tag <tagname>:在當前最新提交上創建一個標簽;
  • git tag <tagname> <commit id>:在指定 commit id 上創建標簽;
  • git tag -a <tagname> -m <'tag information'>:帶提示信息的標簽;
  • git tag:查看所有已建立的標簽;
  • git show <tagname>:查看某個標簽的詳細信息(如建在哪個 commit id 上);
  • git tag -d <tagname>:刪除標簽(本地);
  • git push origin <tagname>:推送標簽到遠程倉庫;對,標簽也要推送!
  • git push origin --tags:一次性推送所有未推送標簽;
  • git push origin :refs/tags/<tagname>:刪除一個遠程標簽(首先要在本地刪除);


手動新建一個 readme.txt 并寫入內容 aaaaa后,用git status查看狀態:

Untracted files

執行git add readme.txt后再次查看狀態:

add 修改后再次查看 status

readme.txt中添加一行bbbbb并保存后,查看狀態:

Changes to be commited:暫存區中有未提交的修改;
Changes not staged for commitnot staged,未將修改添加到暫存區;

再添加一行ccccc后,用git diff readme.txt查看區別:

git diff readme.txt

像這樣,你不斷對文件進行修改,然后不斷提交修改到版本庫里,就好比玩RPG游戲時,每通過一關就會自動把游戲狀態存盤,如果某一關沒過去,你還可以選擇讀取前一關的狀態。有些時候,在打Boss之前,你會手動存盤,以便萬一打Boss失敗了,可以從最近的地方重新開始。Git也是一樣,每當你覺得文件修改到一定程度的時候,就可以“保存一個快照”,這個快照在Git中被稱為commit一旦你把文件改亂了,或者誤刪了文件,還可以從最近的一個commit恢復,然后繼續工作,而不是把幾個月的工作成果全部丟失。

  • git log [--pretty=oneline]:查看日志;
git log
git log --pretty=oneline

需要友情提示的是,你看到的一大串類似3628164...882e1e0的是commit id(版本號),和 SVN 不一樣,Git的commit id不是1,2,3……遞增的數字,而是一個SHA1計算出來的一個非常大的數字,用十六進制表示,而且你看到的commit id和我的肯定不一樣,以你自己的為準。為什么commit id需要用這么一大串數字表示呢?因為Git是分布式的版本控制系統,后面我們還要研究多人在同一個版本庫里工作,如果大家都用1,2,3……作為版本號,那肯定就沖突了。

時光機---回退:將工作區恢復到以前的某個版本

首先,Git必須知道當前版本是哪個版本,在Git中,用HEAD表示當前版本,也就是最新的提交3628164...882e1e0(注意我的提交ID和你的肯定不一樣),上一個版本就是HEAD^,上上一個版本就是HEAD^^,當然往上100個版本寫100個^,比較容易數不過來,所以寫成HEAD~100

HEAD

現在會退到上一個版本:git reset --hard HEAD^

git reset --hard HEAD^

看,readme.txt果然回去了:

readme.txt
但是!如果剛才是手殘,現在想回到add ccccc的那個版本怎么辦??

——有辦法!前提是你剛才的窗口還沒關!

辦法其實還是有的,只要上面的命令行窗口還沒有被關掉,你就可以順著往上找啊找啊,找到那個append GPLcommit id3628164...,于是就可以指定回到未來的某個版本:
$ git reset --hard 3628164 HEAD is now at 3628164 append GPL
版本號沒必要寫全,前幾位就可以了,Git會自動去找。當然也不能只寫前一兩位,因為Git可能會找到多個版本號,就無法確定是哪一個了。

HEAD

現在,你回退到了某個版本,關掉了電腦,第二天早上就后悔了,想恢復到新版本怎么辦?找不到新版本的commit id怎么辦?

在Git中,總是有后悔藥可以吃的。當你用git reset --hard HEAD^回退到add distributed版本時,再想恢復到append GPL,就必須找到append GPLcommit id。Git提供了一個命令git reflog用來記錄你的每一次命令:

$ git reflog
ea34578 HEAD@{0}: reset: moving to HEAD^
3628164 HEAD@{1}: commit: append GPL
ea34578 HEAD@{2}: commit: add distributed
cb926e7 HEAD@{3}: commit (initial): wrote a readme file

現在,你又可以用git reset --hard commit_id回到未來了!


工作區--暫存區--某個分支:
工作區-暫存區-某個分支
撤銷,工作區中,對某個文件最近的修改——即還未stage的修改

git checkout -- readme.txt

命令git checkout -- readme.txt意思就是,把readme.txt文件在工作區的修改全部撤銷,這里有兩種情況:

  • 一種是readme.txt自修改后還沒有被放到暫存區,現在,撤銷修改就回到和版本庫一模一樣的狀態;
  • 一種是readme.txt已經添加到暫存區后,又作了修改,現在,撤銷修改就回到添加到暫存區后的狀態;

總之,就是讓這個文件回到最近一次git commitgit add時的狀態。

discard changes in working directory

上面是撤銷工作區中的修改,若想撤銷暫存區中的呢?

撤銷(unstage)暫存區中,未提交(commit)的修改,重新放回工作區:

git reset HEAD readme.txt

git reset HEAD readme.txt

刪除文件

git rm a.txt

修改若添加到了暫存區,則先要恢復暫存區(git reset HEAD a.txt),再恢復工作區(git checkout -- a.txt)。


連接 Github

注冊賬戶之后,首先需要在 Github 上對本機添加信任(SSH, RSA),步驟
完成后在 Github 上可以看到:

SSH keys

接下來在 Github 上新建一個空的倉庫,然后把本地的倉庫與之關聯,將本地倉庫內容推送到 Github 倉庫:

  1. git remote add origin https://github.com/xiaogmail/learngit.git
  2. git push -u origin master
Quick setup an empty repository

或者,遠程倉庫已經存在,從遠程倉庫克隆到本地:
git clone https://github.com/xiaogmail/learngit.git

創建與合并分支

git checkout -b dev:創建并切換到dev分支;

git checkout -b dev

上面相當于以下兩條命令:
git branch dev:創建dev分支;
git checkout dev:切換到dev分支;

git branch查看分支:

git branch

現在,在readme.txt中加一行new branch然后提交(到dev分支),再git branch master切換回master分支:

提交 dev 后回到 master 分支

這時你發現,readme.txt中最后一行new branch不見了!(用Notepad++需要關閉并重新打開文件)——因為回到了master分支!

現在,把dev分支的內容合并到master分支上:git merge dev
這時會發現readme.txtnew branch的內容又回來了;

git merge dev

注意到上面的Fast-forward信息,Git告訴我們,這次合并是“快進模式”,也就是直接把master指向dev的當前提交,所以合并速度非常快。
當然,也不是每次合并都能Fast-forward,我們后面會講其他方式的合并。

合并完成后的分支狀態:

git merge dev

合并完成后,就可以放心的刪除dev分支了:git branch -d dev

因為創建、合并和刪除分支非常快,所以 Git 鼓勵你使用分支完成某個任務,合并后再刪掉分支,這和直接在 master 分支上工作效果是一樣的,但過程更安全。

解決沖突

現在,你在dev上新增一個提交,切換回master,在master上也新增一個提交,變成了這樣:

分叉了

這時你用git merge dev合并分支:

git merge dev

其中,dev 中 readme.txt 最后一行是 "dev new line",master 中是 "master new line";

這時發現,readme.txt 的內容變了:

git merge dev 失敗后 readme.txt的內容變了!

Git 用 <<<<<<<,=======,>>>>>>> 標記出不同分支的內容

注意上面最后一句話:“Automatic merge failed; fix conficts and then commit the result.”——現在還處于 merge 狀態,只不過需要你手動完成。

我修改為如下:

然后提交,git add readme.txtgit commit -m 'fix conflicts.'
這樣,merge 操作才算手動完成,現在,分支圖:

分叉了
手動合并

看懂分支圖的變化:綠線表示在 master 分支上將 dev 分支的內容合并進來,但 feature1 是不變的!它是被合并的那一個!不動!

仔細想想合并的過程。同一個文件,稍微有點不一樣,就會發生沖突;這時只能手動決定合并后的內容——亦即,隨便改,隨你。

“ 首先 git branch一下你在哪個分支上,本節的例子出現上面的文本應該時在 master 上。那么對于這個文本,想怎么改就怎么改,改成合并后你想要的文本就行。甚至不修改,直接保持上面原文。只要在 merge 操作提示沖突后再進行一個 add 和 commit ,至于進行這個操作前你對 master 分支里的 readme.txt 進行怎樣的修改都行 修改完畢后,git add 然后 git commit,就已經 merge 了。”——網友討論。

所以,git merge 只是一種嘗試,或者一種提示;根據沖突的提示,由你來決定合并后的版本。合并過程與兩個涉及到的分支都沒關系

機智網友的討論:

我說一點自己的理解,不知道對不對啊?造成沖突的原因就是多個分支同時對同一文件進行了修改,有點像是樹節點有了多個兒子,當合并時,HEAD就不知道該往哪里走了,所以只能保留某一個分支的修改內容,然后進行合并。所以,在實際中,我們在同一時間應該利用某一個分支最好只操作固定的文件,避免沖突的發生?不知道我以上說的對不對。

你說的這種辦法絕對不會造成沖突,可是我們在工作學習中不能削足適履吧?已經提供了這種在不同分支中沖突的解決辦法,為什么還要害怕沖突產生呢?

當兩條分支對同一個文件的同一個文本塊進行了不同的修改,并試圖合并時,Git不能自動合并的,稱之為沖突(conflict)。解決沖突需要人工處理


廖老師,你好,我 merge 成功之后(已解決了沖突),發現 master 分支和 feature1 分支中的 readme.txt 的內容不一樣....

廖雪峰:對,因為你解決沖突后 master 多了一個新的 commit,正常情況可以把 master 再 merge 到 feature1 使兩者保持一致

正常情況可以把 master 再 merge 到 feature1 使兩者保持一致,不過沒有必要,因為之前 merge 過了,并且已經修改過了(解決沖突)。修改之后 feature1 就沒有作用了,可以刪掉。


master 是穩定版,然后你此時要開發一個功能 a,你開一個新分支去開發,開發完后再合并到 master,這時 master 才有功能a,大概這樣吧…

用帶參數的 git log 查看分支的合并情況:
git log --graph --pretty=oneline --abbrev-commit

`git log --graph --pretty=oneline --abbrev-commit`

分支管理策略

之前合并分支時,默認用的是Fast-forward模式,但這種模式下,刪除分支后,會丟掉分支信息

默認的Fast-forward和用參數--no-ff關閉快速模式:

Fast-forward
--no-ff
git merge dev
git merge --no-ff dev

刪除dev分支后再看:

git branch -d dev
git branch -d dev

重新做了個實驗,在 master 中新建 a.txt,空的;新建并切換到分支 dev,分3次添加 aaaa,bbbb,cccc;再切換回 master,合并,分別用默認 Fast-forward 和 --no-ff ;最后刪除 dev 分支,查看分支圖:

git merge dev
git merge --no-ff dev -m 'master merge dev with --no-ff'

也許最關鍵的后果是,造成了 dev 分支 commit 記錄和 master 的 commit 記錄的混亂吧。想想 Fast-forward 的實現方式,移動指針。
而用 --no-ff 就可以在即使 dev 刪除后也能保留 dev 的 commit 記錄,清晰的區分開來。


另,當有沖突時,就不再是 Fast-forward 了(你都動手了),這時就轉為了 --no-ff,自然可以保留 dev 分支記錄 or 合并記錄。不要迷惑了。

下面這張圖完美解釋了這個問題!

問題的關鍵點在于 master 有沒有diverged!**


分支策略

在實際開發中,我們應該按照幾個基本原則進行分支管理:
首先,master分支應該是非常穩定的,也就是僅用來發布新版本,平時不能在上面干活;
那在哪干活呢?干活都在dev分支上,也就是說,dev分支是不穩定的,到某個時候,比如1.0版本發布時,再把dev分支合并到master上,在master分支發布1.0版本;
你和你的小伙伴們每個人都在dev分支上干活,每個人都有自己的分支,時不時地往dev分支上合并就可以了。
所以,團隊合作的分支看起來就像這樣:

合并分支時,加上--no-ff參數就可以用普通模式合并,合并后的歷史有分支,能看出來曾經做過合并,而Fast forward合并就看不出來曾經做過合并。

保存當前工作 [現場]

在切換分支前,當前的工作現場必須是“working tree clean”的狀態;即不能有沒 staged 的修改,或未 commit 的 stage;否則在切換前會有提示:

working tree not clean before git checkout another-branch

Your local changes to the following files would be overwritten by checkout: a.txt. Please commit your changes or stash them before you switch branches. Aborting.

提示要么提交,要么 stash,隱藏當前工作現場;

git stash:保存并隱藏當前工作現場,待以后恢復;(stash:隱藏)

git stash

然后就可以愉快的切換分支了。

再回來,用git stash list查看隱藏的工作現場:

git stash list

然后用git stash pop恢復并刪除分支:

git stash pop
  • git stash apply:恢復工作現場;
  • git stash drop:刪除隱藏的工作現場;
  • git stash pop:恢復并刪除;

修復bug時,我們會通過創建新的bug分支進行修復,然后合并,最后刪除;

當手頭工作沒有完成時,先把工作現場git stash一下,然后去修復bug,修復后,再git stash pop,回到工作現場。

刪除分支時的一點小問題

軟件開發中,總有無窮無盡的新的功能要不斷添加進來。

添加一個新功能時,你肯定不希望因為一些實驗性質的代碼,把主分支搞亂了,所以,每添加一個新功能,最好新建一個feature分支,在上面開發,完成后,合并,最后,刪除該feature分支。

但就在 feature 分支的新功能開發完畢,切換回 dev 分支準備合并時,接到上級命令,因經費不足,新功能必須取消!

雖然白干了,但是這個分支還是必須就地銷毀:git branch -d dev

git branch -d dev

但是提示:dev 分支還沒有被合并,如果確定要刪除,用git branch -D dev

照做,OK.

多人協作

當你從遠程倉庫克隆時,實際上Git自動把本地的 master 分支和遠程的master 分支對應起來了,并且,遠程倉庫的默認名稱是 origin 。

git remote:查看遠程倉庫信息;
或者git remote -v查看更詳細的信息:

git remote -v

上面顯示了可以抓取和推送的 origin 的地址。如果沒有推送權限,就看不到 push 的地址。

git push origin <branch-name>:推送某個分支到遠程倉庫;

原來你的遠程 origin 倉庫里只有 master 分支,現在你推送 dev 分支,那么 origin 里就會新出現一個 dev 分支。origin 是 倉 庫 名 ,可以容納很多分支

現在,另一個人參與進來,他在他的電腦上 clone 這個倉庫:git clone https://xxxxxx.git但是,他用git branch查看分支時,發現 只 能 [看 到] master 分支,dev 分支 [看] 不 到!:

clone 下來的只有 master 分支,沒有 dev !

是的,這時需要你手動把他找出來:
git checkout -b dev origin/dev

git checkout -b dev origin/dev

我這里為什么猜測是 [看不到],而不是根本沒有拷貝下來?因為這句命令回車后沒有拷貝的過程!瞬間完成。

就行來就可以在本地的 dev 分支上繼續工作了。

多人協作

完整故事看這里


多人協作的工作模式通常是這樣:

  1. 首先,可以試圖用git push origin branch-name推送自己的修改;
  2. 如果推送失敗,則因為遠程分支比你的本地更新,需要先用git pull試圖合并;
  3. 如果合并有沖突,則解決沖突,并在本地提交;
  4. 沒有沖突或者解決掉沖突后,再用git push origin branch-name推送就能成功!

如果git pull提示 “no tracking information”,則說明本地分支和遠程分支的鏈接關系沒有創建,用命令git branch --set-upstream-to=origin/branch-name

這就是多人協作的工作模式,一旦熟悉了,就非常簡單。


使用標簽

標簽(tag)也指向某個 commit,作用是為某次 commit 取個別名——因為 commit id 是一串無規律的數字,記不住。類似于 ip 地址和域名的關系。

其余

  • 忽略某些文件時,需要編寫.gitignore
  • .gitignore文件本身要放到版本庫里,并且可以對.gitignore做版本管理!
為命令配置別名

上面哪個顯示分支圖的命令還記得嗎?
git log --graph --pretty=oneline --abbrev-commit
還有一個顏色、格式更好,但更長的版本:
git log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit

效果圖(顯示出了時間,不同的顏色)

太長了,記不住怎么辦?設置一個別名。
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"

lg就是后面一大串的別名。

然后就可以git lg了!

git 全局的配置文件在C:\Users\xiao\.gitconfig

.gitconfig

Done!

終于到了期末總結的時刻了!

經過幾天的學習,相信你對Git已經初步掌握。一開始,可能覺得Git上手比較困難,尤其是已經熟悉SVN的童鞋,沒關系,多操練幾次,就會越用越順手。

Git雖然極其強大,命令繁多,但常用的就那么十來個,掌握好這十幾個常用命令,你已經可以得心應手地使用Git了。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,572評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,071評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,409評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,569評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,360評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,895評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,979評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,123評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,643評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,559評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,742評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,250評論 5 356
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,981評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,363評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,622評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,354評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,707評論 2 370

推薦閱讀更多精彩內容