Git的点点滴滴,附带Android Studio中的操作(二):用Git备份代码

一 Git配置和仓库初始化

下面会介绍Git的使用,每个小节里会讲解各个功能在命令行中的实现方式,并在每小节的最后介绍在Android Studio中的图形界面里怎么使用对应的功能。

01 Git配置

在安装完Git后,会有一个叫做Git Bash的程序,打开之后会出现一个跟Linux命令行操作界面神似的命令行窗口,其中可以输入各种Git指令和一些Linux指令。

在使用Git之前,需要进行一步设置,在命令行中输入:

$ git config --global user.name "Your Name"
$ git config --global user.email "email@example.com"

这两条指令就相当于给自己的电脑取了个名字。在之后的每次提交(备份)中,这两个属性都会被添加到那一次提交生成的提交对象中。在协同开发时,大家可以通过这个名字来区分是谁完成了这个功能,是谁写出了那个Bug。

当然Git中可以进行的设置还有很多,有兴趣的可以查阅git config这个命令。另外,--global这个参数表示电脑上的所有仓库都会使用这个名字,当然你也可以给每个仓库指定不同的用户名和Email地址。

在Android Studio中使用Git还需进行如下配置。
在Android Studio中使用Git需要将安装完成的Git.exe文件配置到Android Stdudio中。具体步骤如下,首先点击File->Settings打开Settings对话框,接着点击Version Control->Git进入相应目录,在Path to Git executable中填入Git.exe所在位置。

之后点击Test进行测试,如果弹出成功信息,则配置完成。

02 创建Git仓库

在Git中,创建Git仓库对应的指令为git init,它会把当前目录初始化为一个Git仓库。使用命令行的话,你可以先把Android工程建好,再是一顿cdmkdirls来到相应的目录,执行git init来初始化仓库,也可以先建立好仓库,再把工程建在里面,没毛病!

如果用Android Studio初始化仓库。
首先新建一个工程。再点击VCS->Create Git Repository,会弹出一个对话框,让你选择Git仓库的初始化目录,一般都会选择工程的根目录。

注意: 其实在Android Studio中也可以打命令行,在底部的Terminal栏目里输入命令即可。但是因为各种别扭,打命令行还是喜欢用Git bash。

点击OK即可完成仓库的创建。 在新建Git仓库之后,会发现Android Studio底下多出了一个Version Control栏目。在其中可以进行许多方便的Git操作,包括分支的图形化显示,文件状态的浏览等。细心的同学应该会发现其中的文件是红色的,这里的颜色表示了文件的状态——文件还没有被加入到暂存区中(后面会具体讲暂存区)。


二 用Git备份代码

我们通常是这么备份代码的。第一步,在上一个备份点继续开发。第二步,在想要备份的时候,打个包,存到电脑上,如果怕电脑中病毒瘫痪之类的,可能还会发一份到云盘上,第三步,继续在这一个备份点上开发,……。在开发中,考虑到包的大小和一些自动生成的配置文件和编译过程中产生的文件等,会在上述步骤中再添加一步。即在备份之前,把需要的改动挑选出来,再进行备份。

Git备份代码,其实也就是这三步。

  1. 在上一个版本的基础上继续开发,修改代码。
  2. git add或者git rm指令,将需要的改动添加到暂存区(顾名思义,一个暂存文件的区域),对应上面的挑选改动操作。
  3. git commit指令,将暂存区中的改动与上一个提交(备份)结合,形成一个新的提交(备份),对应上述操作中的备份操作。

注意:这里的改动并不单单指对原文件的修改,也包括创建文件,删除文件。

01 在本地备份代码

在Git中用git addgit rm操作来添加改动到暂存区,并用git commit来生成一个提交(备份)。接下来分别介绍添加文件修改删除这三种改动添加到到暂存区的方法和生成一次提交的方法。

关于暂存区到底是个什么东西。
我们把平时看到的电脑上的目录叫做工作区,里面是我们实际操作的文件。而暂存里面一开始会包含上个提交时的所有文件,然后我们会通过git addgit rm操作来把工作区里的改动添加到暂存区,比如添加新文件到暂存区,把修改后的文件添加到暂存区以及删除暂存区中的文件。当最后提交时,Git把暂存区中的所有文件组织成一棵树,再加入时间,作者等信息形成一个commit对象,再把commit对象与上一次提交生成的commit对象连接起来,就完成了一次新的提交。(上述表述不是非常严谨额,大家别太较真,意思懂了就行。Git管理文件的方式与Unix的文件系统类似,想具体了解可以去看Git官网的教程)

在新创建Git仓库后,所有文件都还没有加入到版本控制系统中,当前仓库是空的。这里有的同学就奇怪了???你不是用git init在这个目录下初始化了Git仓库吗,我这个目录下好多文件呢,你怎么说他是空的呢。!!!注意,当前目录下的文件并不属于Git仓库!!!在git init之后,会在当前目录下生成一个.git目录(在windows里这个目录隐藏的,设置了显示隐藏文件之后可以看到),里面有一个objects目录,这个目录下的文件才是属于Git仓库的。刚初始化的仓库的objects目录有两个目录,一个info,一个pack,不过里面啥也没有,都是空的。

这时,对于Git来说,存在了许多新建文件。在命令行中输入git status可以查看仓库的状态,其中的Untracked files中的内容,就是我们还未添加的改动——添加文件。

改动类型一:添加文件

在上面的git status中显示的untracked files均是在当前版本中还未添加到暂存区里的文件。可以用git add <file>来将他们加入暂存区。在加入之后用git status查看仓库的状态。

$ git add app/src/main/java/com/bigboss/blelock/myapplication/MainActivity.java
$ git status

会发现,多了一段提示,Changes to be committed(等待提交的改动),其中显示的就是new file(新文件)。这说明,我们已经将需要的改动添加到暂存区了。这个时候再去查看.git\objects目录,会发现多了一个文件。

添加完成后用git commit -m "提交信息"将暂存区中的内容生成一个提交(备份)。

$ git commit -m "添加了MainActivity"

git log指令可以查看当前的提交历史。可以看到多了一个提交,提交信息就是我们刚才输入的添加了MainActivity。从这里也可以看到,在第一步Git配置时,设置的用户名和邮箱都自动添加到了提交信息中。

改动类型二:删除文件

在我们删除文件后,可以通过git rm <file>来把暂存区中的文件也给删掉,从而将改动更新到暂存区。在我们的第一个版本中,我们添加了一个新的文件MainActivity.java,下面我们把它删除,并添加另一个activity_main.xml文件(为了方便修改操作的演示)。

在把工作区中的MainActivity.java删除后,运行git status,Git会很机智的告诉我们MainActivity.java已经被删除了,但还没有更新到暂存区。

我们用git rm <file>将对MainActivity.java的改动更新到暂存区,并添加activity_main.xml到暂存区里。

$ git rm app/src/main/java/com/bigboss/blelock/myapplication/MainActivity.java
$ git add app/src/main/res/layout/activity_main.xml

执行完成后,用git status查看仓库状态。可以看到Changes to be commited里有了deleted和new file两条改动信息。

最后提交一下修改。

$ git commit -m "删除了MainActivity.java,添加了activity_main.xml"
$ git log

改动类型三:修改文件

在我们修改了文件之后,将修改更新到暂存区的操作也是git add <file>,这里可能有同学会觉得奇怪,为什么修改文件也用git addadd不是添加文件的意思吗,其实从本质上讲Git对已修改文件的处理方式就是将修改后的文件整个加入到暂存区替换掉原文件,那用add更新修改也就顺理成章了。

现在我在activity_main.xml的最后加一行modifyTest,运行git status会有下面的modified提示。

我们用git add <file>来把修改添加到暂存区,然后查看仓库状态。

$ git add app/src/main/res/layout/activity_main.xml
$ git status

最后提交一下修改。再用git log 查看一下提交历史。

$ git commit -m "在activity_main.xml最后加了一行,modifyTest"
$ git log

提交历史如下,又生成了一个提交了哈。

更新所有改动到暂存区并提交

大部分的时候,我们会把所有的改动都更新到缓存区并提交,可以使用git commit -am "提交信息",它会自动把所有已经跟踪过的文件暂存起来一并提交,包括修改和删除,他是git add -ugit commit -m "提交信息"的结合。如果要把全部文件的添加,修改,删除三种改动全部添加到暂存区去,可以用git add -A

通常我们还需要忽略一些指定的文件,比如在java编译后生成的.class文件等,这可以通过配置.gitignore文件来完成。具体见.gitignore的使用这一节。

至此,添加三种改动到暂存区的方式就讲完了,大家可以组合这三种操作完成各种各样的任务!

git status原理

在用git status查看仓库状态时,经常会看到Untracked filesChanges not staged for commitChanges to be committed三个标题。大家大概能知道里面的内容是什么意思,但有时还是会感到迷惑。接下来我们会介绍这三个标题下内容的由来。

这三个标题中的内容是根据三个文件树产生的。这三个文件树分别为工作区,暂存区和上一个提交中的文件区(仓库刚初始化的时候,没有提交,相当于文件树为空)。Untracked files显示的是工作区中存在而暂存区中没有的文件,通常为新建的文件,而Changes not staged for commit里是工作区中和暂存区中内容不同的文件,通常是因为修改了文件,显示为modified,以及暂存区里存在但工作区里没有的文件,通常是因为删除了文件,显示为deleted。而Changes to be committed里显示的是暂存区里有,但是上一次提交中没有的内容。

Android Studio中的相应操作
先切换到Version Control栏目的子栏目local Changes中,在这里可以看到修改的文件。在里面会看到两个目录,一个是Defult,一个是Unversioned Files。前者中显示的是Git命令行中Changes not staged for commit栏目的对应文件,后者中显示的是未添加到暂存区的文件。

相比命令行的方式,图形界面有更方便的方法来生成一个提交。用户可以直接勾选所需添加的改动,然后直接提交。(Git会有一个暂存区的存在,其中一个原因就是为了模拟挑选改动的行为)。在Android Studio中,点击图中框出的按钮会弹出Commit Changes对话框,来进行提交操作。

之后可以在弹出的窗口中,选择要更新到暂存区的文件,填写提交信息,完成后就按下提交即可完成。

在Version Control的Log子栏目下可以已图形化的方式查看提交历史,其中HEAD标志了当前所处的版本,master标志了master分支的位置。

02 撤销修改

撤销修改有关的命令主要就是两个,git checkout -- <file>git reset HEAD <file>,关于这两个命令,主要记住两点。

  • git checkout -- <file>是把工作目录下的文件用暂存区里的文件代替
  • git reset HEAD <file>是把暂存区里的文件用上一次提交时的文件代替。

先看一个例子来了解他们的区别。在上一次修改activity_main.xml后,这个文件内容如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.bigboss.blelock.myapplication.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

</android.support.constraint.ConstraintLayout>

modifyTest

我们把最后一行modifyTest删掉,先不更新修改到暂存区,然后执行以下指令

$ git checkout -- app/src/main/res/layout/activity_main.xml

再回到activity_main.xml中,会发现删除的内容又回来了。

这次我们再把最后一行modifyTest删掉,执行以下指令,将修改更新到暂存区再执行git checkout

$ git add app/src/main/res/layout/activity_main.xml
$ git checkout -- app/src/main/res/layout/activity_main.xml

再回到activity_main.xml中,会发现删除的内容并没有回来。

为什么呢?因为git checkout -- <file>撤销修改是把暂存区对应的文件替换工作目录下的文件,所以没有更新到暂存区的修改可以撤销,而更新到暂存区的修改不能撤销。

如果要取消添加到暂存区的修改可以采用git reset HEAD <file>,这个命令可以撤销暂存区里对应文件的修改,但工作目录中的文件不会改变,因为这个命令是用上一次提交中的文件替换暂存区的文件。如果想把工作目录和暂存区中的文件都恢复到上次提交时的样子,可以用git reset HEAD <file>git checkout -- <file>

在工作中,如果你的工作还没有添加到暂存区,那么用git checkout -- <file>即可,如果添加到了暂存区,想要恢复,可以先git reset HEAD <file>git checkout -- <file>

Android Studio中的相应操作
在Android Studio中撤销修改非常简单,在Version Control中选中要撤销修改的文件,鼠标右键,在弹出的菜单中选择Revert即可撤销修改,注意这边的撤销修改是恢复到上次提交时的样子,相当于使用git reset <file>git checkout <file>

03 版本回退

在Git中你可以使用git reset commitID把当前版本回退到之前提交的任意一个版本中。是不是觉得很熟悉!在上一节中使用过这样一个指令,git reset HEAD <file>,这其实是同一个指令!在Git中,HEAD表示最近一次提交,而最近一次提交的上一次提交可以用HEAD^,那上上一次呢?HEAD^^,上上上一一次?HEAD^^^,那……你懂得。还记得git reset HEAD <file>的作用吗?用最近一次提交中的文件替代暂存区中的文件。仔细想一想,其实版本回退就把所有文件都替换掉就好了!在git reset指令中,在不加<file>这个参数后,会把整个暂存区用对应提交中的文件替换掉。

特别注意一下,git reset commitID只是回退了暂存区中的文件,工作区中的文件是不会改变的。举个栗子。目前我们的activity_main.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.bigboss.blelock.myapplication.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

</android.support.constraint.ConstraintLayout>

modifyTest

我们回退到上一个版本,在上一个版本中我们的activity_main.xml中还没有添加最后一行。

$ git reset HEAD^

执行后,查看activity_main.xml,发现并没有改变!因为git reset commitID回退的是暂存区的内容,工作区的内容是不变的。如果你不相信,可以用git status查看一下仓库状态,里面应该会有一条Changes not staged for commit,里面的内容是modified: activity_main.xml。如果想把工作区也回退到上一个版本中的样子,可以在reset之后,执行git checkout -- .将当前目录用暂存区的内容替代。或者可以直接使用git reset --hard commitID,其中的--hard参数会使工作区和暂存区都被恢复成上一次提交时的样子。

要回退的版本可以直接用提交的SHA1值指定。提交的SHA1值可以用git log中看到。

用SHA1值来回退到上一个版本就像这样。

git reset 952979b2057f6324f204130c88ab8d7452f33489

git reset命令可以将当前版本设置为任意一个提交,只要知道那个提交的SHA1值,就能用git reset命令将它设置为当前版本。现在我们要把当前版本跳转回去,回到那个添加了modifyTest的版本去,我们用git log命令来查看这个版本的SHA1值,发现......并没有!

git log只会显示当前版本之前的提交历史。不过还是有办法的,我们用git reflog指令,他记录了HEAD这个头指针变动的历史。

用查找到的版本号进行git reset操作就可以回去了。

Android Studio中的相应操作
在Android Studio中进行版本地方法如图所示,在Version Control的Log下,选中要跳转的版本,右键右键在弹出的菜单中,选择Reset Current Branch to Here即可。


04 .gitignore文件的使用

一般在使用Git时,会使用git add -A将工作区里的所有文件都更新到暂存区,但是总有些文件是我们不想添加进版本控制系统的(通常是一些自动生成的文件,想编译后产生的文件),这时要么一个一个添加文件,要么先全部添加,再把不要的删掉,很不方便。而且在每次用git status总会有大量的红字,提示我们有文件没添加进版本管理。使用.gitignore文件可以告诉Git哪些文件是不想纳入版本管理的,让Git把这些文件忽略掉。

在Android Studio中,有两个.gitignore文件,一个是Project根目录下的,一个是module下的。对于Android项目,根目录下的.gitignore文件可以如下配置。

# Built application files
*.apk
*.ap_

# Files for the ART/Dalvik VM
*.dex

# Java class files
*.class

# Generated files
bin/
gen/
out/

# Gradle files
.gradle/
build/

# Local configuration file (sdk path, etc)
local.properties

# Proguard folder generated by Eclipse
proguard/

# Log Files
*.log

# Android Studio Navigation editor temp files
.navigation/

# Android Studio captures folder
captures/

# Intellij
*.iml
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/dictionaries
.idea/libraries

# Keystore files
*.jks

# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild

# Google Services (e.g. APIs or Firebase)
google-services.json

# Freeline
freeline.py
freeline/
freeline_project_description.json

module下的.gitignore文件可以如下配置:

/build
*.iml  

如果还有什么需要忽略的文件,可以自行添加,添加的语法如上,其中#开头的是注释,*表所有,像*.iml表示所有后缀为.iml的文件。

配置前后用git status查看文件状态,可以发现我们指定的忽略文件已经被忽略了。

如果一个文件已经被检入到了暂存区里面,那么即使在.gitignore文件里添加这个文件名,Git也不会忽略他。所以最好在一开始的时候就把.gitignore给配置好。如果很不幸地出现了这种情况,用下面的指令把相应的文件从暂存区里面删除即可。

# --cached参数表明只删除暂存区里的文件,不加时工作区和暂存区里的文件都会被删除
$ git rm --cached FILENAME

既然已经把不需要的文件都忽略了,以后添加改动和提交只需要把他们全加上了!执行以下指令。

$ git add .
$ git commit -m "添加了忽略规则"

现在再用git status查看仓库状态,显示当前没有任何改动,工作树(工作区)是干净的。其实早就想这么干的,红字看的真心难受。。。

帮助: GitHub 有一个十分详细的针对数十种项目及语言的 .gitignore 文件列表,你可以在
https://github.com/github/gitignore 找到它.


05 备份代码到远程仓库

由于电脑可能会中途报废,我们可能需要个像云盘一样的东西用来备份。又或者在好多个地方有好多台电脑,今天在那里工作明天在这里工作,我们就需要一个地方来中转代码。又或者需要进行协同开发……

这里我们使用Github来创建远程仓库,当然也可以采用别的Git仓库托管服务,像码云,Bitbucket等,当然自己搭也是可以的,在Git官网上有详细的教程。Github账号是必须的,请自行注册。既然要在网络中传输数据,那必然要涉及到协议。目前Git传输数据最常用的两种协议是SSH和HTTPS。

使用SSH协议的方式

1. 配置SSH Key

在命令行中执行以下命令,生成SSH Key。

$ ssh-keygen -t rsa -C "youremail@example.com"   // 把邮箱替换成自己的

输入后,他会让我们输入Key存放的位置,如果直接回车,那么默认就是冒号前面那段路径了,之后要根据这个路径找到Key。

之后他还会叫你两次输入密码,如果没什么重要的东西,直接回车就好了。成功后应该是下面这个样子的。

然后来到生成Key的目录下面,有下图所示的两个文件,打开后缀为.pub的文件(这个是公钥,另一个是私钥),过会儿我们会要把它放到github的账户里。

按下图的步骤把SSH添加到账户里,按下Add SSH Key,就完成了SSH Key的配置。

2. 创建远程仓库

按下图进入创建远程仓库页面。

按下图创建一个远程仓库。Github上的私人仓库是要钱的,7美元一个月哈。虽然是仓库公开的,但是因为有ssh key,别人是不能直接修改你的代码的,不过他们可以看到你的代码。

点击创建后,就拥有自己的远程仓库啦!

3. 在本地添加远程仓库

现在我们已经创建好远程仓库了,我们在本地仓库把它添加上去,就可以把代码备份到远程库了。添加远程库的命令如下。

git remote add <shortname> <url>

其中shortname相当于是url的简称,以后用shortname就可以代表urlurl是远程仓库的地址,可以在如下页面中得到。

一般用origin表示远程库。在我们的仓库里,执行以下命令。

$ git remote add origin git@github.com:WoHohohoho/MyApplication.git

可以用git remote来查看现有的远程库,上一个命令成功后再执行可以看到多了一个origin

4. 把本地仓库的内容push到远程仓库

在添加完远程库后,可以用git push [remote-name] [branch-name]命令来将本地仓库中的内容推送到远程仓库上。其中remote-name是远程仓库名,就是上一步中我们设置的shortnamebranch-name是分支名,分支的具体内容下面再介绍。git push可以把本地的提交推送到远程仓库中,在执行时,本地仓库与远成仓库会比较提交历史,把远程仓库没有的提交挑选出来,然后发上去,完成更新。

git push对应的还有git pull [remote-name] [branch-name],push是推,而pull是拉,当我们在另一台电脑上完成工作并推送提交到远程仓库后,为了在原来的电脑上继续工作,我们需要把远程仓库中的更新拉下来,更新本地仓库。

注意: 在使用git pull时,要保证本地仓库是最新的,即远程仓库中所有的提交本地都需要有,不然Git会提示pull操作失败。在一个人开发时,因为自己知道自己的代码是否是最新的,所以简单地使用pushpull就可以了。在多人开发中,由于别人也会向远程仓库提交代码,在每次push前需要先试探性的获取远程的更新,没有的话就直接push,有的话需要把更新合并到本地的代码中,由于这涉及到分支和合并,之后再详细讲。

仓库初始化时,会默认创建一个master分支,我们的版本现在都在这个分支上,现在我们把这个分支推送上去就好了。

在我们的仓库里输入下列指令。

$ git push origin master

执行完成后,远程仓库里就存在了一份一模一样的工程。

以后每有更新,用git push将改动更新到远程仓库即可。

使用HTTPS协议的方式

使用HTTPS协议操作起来比较简单。只要从使用SSH协议的第三步开始,将远程仓库的url换成https形式即可。

之后操作和SSH方式相同,不过在push和之后会提到的fetch(拉取)时,会要求验证账号和密码,不过可以通过设置,来保存账户名和密码,而且一些客户端可以帮助存取账户名和密码,十分方便。HTTPS虽然使用起来很方便,但服务器搭建时配置HTTPS比配置SSH麻烦许多。

Android Studio中的相应操作
可以直接在Android Studio连接Github,建立远程仓库,完成推送。首先需要在Android Studio中设置对应Github的账号和密码。操作路径为File->Settings->Version Control->Github

其中Clone git repositories using ssh这个选项勾选了,就会使用ssh协议,不勾选就会使用https协议。用Test可以测试是否能够连接上Github。使用ssh协议的话,在创建之前需要配置SSH Key,方式和前面相同。

点击之后,可能会要求你输入密码等,最后会弹出一个如下对话框,填写信息,按下Share按钮,就完成了创建远程仓库,在本地添加远程仓库,推送代码到远程仓库的一系列操作,十分方便。

Android Studio中的push操作和pull操作分别是VCS->Git->PushVCS->Git->Pull

06 克隆

上一小节我们讲了怎么创建一个远程仓库并把本地仓库同步到上面去,这节会讲如何将远程仓库拷贝到本地来。以后,只要有一台能联网的电脑,我们就能继续我们的工作。

在Git中,可以用git clone <remote-url> <local-directory>来克隆远程仓库到本地。接下来,我们试着把上一节中创建的远程仓库clone到本地来。

我们执行以下命令,其中remote-url就是我们在创建远程仓库时得到的远程仓库的地址,local-directory指明了我们要把仓库放在这个目录(文件夹)里,如果这个目录不存在,Git会自动帮我们新建。

$ git clone git@github.com:WoHohohoho/MyApplication.git ~/Desktop/MyApplicationCloneVersion

执行完成后,打开对应目录,会发现东西都已经拷下来了,比U盘什么的方便多了。

Android Studio中的相应操作
Android Studio中的Clone操作沿着VCS->Git->Clone路径可以找到。

之后填写相关参数即可,点击Clone即可。

下一篇: Git的点点滴滴,附带Android Studio中的操作(三):Git中的分支

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容