zoukankan      html  css  js  c++  java
  • 版本管理工具 —— SVN

    想想我们在开发过程中是不是会遇到这样的情况:
      今天写了很长的一段代码,觉得不合理,然后删了,第二天突然发现昨天的那段代码才是正确的,那怎么办,也无法撤销删除的代码?
      还有团队中多人共同开发一个项目,如何多人同时开发一个文件而不会导致冲突覆盖的情况发生?
      就算是你自己写代码,写小项目,如何管理这些项目?如何控制他们的版本?
     
    解决这些问题就需要SVN啦:
    SVN(Subversion):代码版本管理软件,你可以将文档、项目、代码放到SVN的中央仓库(Repository)中,这个仓库就像一个文件服务器,不过它会记住文件每一次的变动(包括日期、修改人等等),这样你就可以把文件恢复到指定日期的版本。同时,多人开发时,可以将项目从仓库中下载到本地,自己开发自己的模块并提交,就算有冲突或覆盖,也能及时发现并回退到之前的版本。只要你在每次修改和提交代码之前将代码更新到最新的版本,一般是不会发生覆盖别人代码的情况的。
     
    从上面的描述就可以看出SVN分为服务端和客户端了,下面就展示下服务端和客户端的安装过程,及使用。
    一、SVN服务端安装及使用
    二、安装客户端及使用
    三、账号和权限设置
    四、SVN客户端使用 -- 基本操作
    五、SVN客户端使用 -- 冲突解决(重点)
    六、在IntelliJ IDEA中使用SVN
    七、分支、合并、切换
    八、使用http方式访问SVN
    九、SVN对比Git
     
    一、SVN服务端安装及使用
      1.双击安装SVN服务端、一路Next,安装完成。我这里将服务端安装到我本地的虚拟机内,我的虚拟机是win8 32位的。
      
      2.检查安装是否成功:svnserve --version 显示如下信息则表示成功了。
      
      Subversion 在安装时,同JAVA 的开发环境(JDK)的安装一样,同样会自动的把安装目录下的bin目录设置到系统变量中去。如果你使用的绿色版,那么设置系统变量这个步骤就得你自己手动来设置了。
      
      3.创建SVN仓库:
      我在G盘建了一个SVNServer目录作为SVN的服务器根目录,然后建了一个所有项目的根目录SVNServersvn epo,然后分别建了doc(存文档)、trunk(存项目)目录。
      建议大家从一开始无论做什么都要规范,包括命名,存放位置等等。
      
     
      现在假如我要开发一个scm项目,则在trunk下建一个scm仓库用于存放该项目(这种方式是一个项目作为一个服务):> svnadmin create G:SVNServersvn epo runkscm
      可以为不同的项目创建对应的仓库,分别存储不同项目的代码文件。
      
      4.启动这个项目的服务:> svnserve -d -r G:SVNServersvn epo runkscm
      这种启动方式,启动成功后,当前命令窗口不能关闭,关闭则服务就关闭了。
      可以重新打开一个窗口,使用netstat -an检查端口,svn的默认端口是3690, 有的话则表明svn服务启动成功。
      
      5.将仓库中的项目检出:
      现在我将F盘作为我的本地开发目录,在F盘下建立repo目录,用来存储从服务器检出的项目
      > svn checkout svn://localhost F: eposcm
      这里使用命令行的方式,我将scm项目检出到F盘的repo目录下,检出后可以在scm里看到.svn(本地svn管理)。记得勾选查看隐藏文件才能看到。
      在说明下命令参数:checkout则是检出命令;svn:\localhost则是启动的svn服务器地址,这里指向的就是scm仓库;F: eposcm 检出地址。
      
      6.创建并提交
      在还没有创建svn用户的时候,如果想要向svn提交文件,需修改如下配置:允许匿名用户有写的权限,不过这个一般是不开放的。
      
      之后我在scm下创建了controller文件夹,并在里面创建了LoginController.java文件。
      需要注意的是:新目录内部的文件不能直接提交,必须是目录本身已经提交给仓库了,该目录的文件才可以单独进行提交操作。
      
      加入到本地.svn版本控制中:svn add F: eposcmcontroller
      
      提交到svn仓库:svn commit -m 'controller代码' F: eposcmcontroller
      -m 后跟的是此次提交文件的备注。提交后的版本为1
      
      7.然后你可以在svn服务端的这个目录下看到你提交的版本日志信息(上面显示的版本为1),用SVN客户端你可以看到详细的版本信息,以后你也可以回退到任意版本了。
      用户每提交一次,这里就会产生一个新的版本号。
      
      然后这个目录下就可以看到文件内容详细信息,不过服务端的管理一般都是不用你去操心的,这里只是介绍下。
      
     
    上面就是SVN服务端的安装及一些简单的使用了,但是有几个明显的不好的地方:使用命令行操作太麻烦了;每次启动SVN服务都必须手动启动,且要保持命令窗口一直开着,如果多个项目还得启动多个窗口。所以,后面就用SVN客户端来操作。
     
     二、安装客户端及使用
      1.在安装客户端之前,首先我们需要安装SVN服务器并制作成windows服务,用于作为SVN的仓库,安装步奏如上。
      服务端安装成功之后,以管理员身份运行cmd,输入如下命令创建成windows服务:
      > sc create SVN-Service binpath="E:Program FilesSlikSvninsvnserve.exe --service -r G:SVNServer" displayname="SVN-Server" start=auto depend=Tcpip
      参数: 
        binpath为执行命令所在的路径
        -r 为仓库的路径:这里配置的多仓库,也就是 h说你可以在SVNServer下建立很多仓库。你可以看成svn://localhost指向G:SVNServer。这里G:SVNServer是所有仓库的根目录。
        displayname则是SVN服务的显示名称。
      创建成功后,可以运行services.msc打开服务,查看SVN-Server是否制作成功。然后启动SVN-Server。
      
      我这里是直接改的注册表,cmd每次启动就是管理员身份:如果你发现你执行不了,可以添加脚本的方式执行:
      比如:新建一个create.bat文件,复制要执行的命令粘贴到这个文件里;保存,然后右键"以管理员身份运行"即可。
     
      2.双击安装SVN客户端,一路Next。
      
      3.安装成功:在任意位置,右键能看到如下的标志,则客户端安装成功。
      
      3.创建SVN仓库
      第1步里,创建了SVN服务的根目录G:SVNServer,你可以直接在这个目录下创建项目仓库,比如scm,然后就以svn://localhost/scm访问这个项目。
      我这里将G:SVNServersvn epo作为仓库:
        
      然后,点击Create folder structure,创建SVN规范的结构目录,会为仓库自动生成trunk/branches/tags三个目录,这是SVN目录的规范。
      
      4.然后,你可以到其它盘去浏览当前仓库的目录结构:
      
      输入访问的地址:
      
      可以看到repo仓库的目录结构了。
      
     
    三、账号和权限设置
      前面的讲解了安装及简单的使用,使用的是匿名账户,这样安全性极低,如果是多人开发,肯定会导致冲突的。所以我们先学习设置账号和权限再继续后面的使用。
      所有与账号和权限相关的都在仓库的conf目录下配置。
      
      1.定义所有认证和授权政策:svnserve.conf
      ① anon-access 
        匿名用户的访问权限,应该是什么访问权限都没有
        anon-access = none  
      ② auth-access
        认证用户授权拥有写的权限
        auth-access = write
      ③ password-db
        指定用户的认证文件为passwd文件(需要去掉#才能引入这个配置文件)
        password-db = passwd
      ④ authz-db
        指定用户的授权文件为authz文件(需要去掉#才能引入这个配置文件)  
        authz-db = authz
      2.存放项目成员账户信息:password
      等号左边代表用户名,等号右边代表密码;这里我按部门添加了如下一些用户:
      
      3.复杂的群主授权控制:authz
      如果用户较少,可以不用分组,直接为用户设置权限。
      
      比如我这里的配置:
      
      
      4.再次访问的时候就需要你输入用户名和密码了:
      
     
    四、SVN客户端使用 -- 基本操作
      在公司项目开发中,SVN服务器一般是搭建在一个局域网主机上,由管理员(或运维人员)管理着。我们的电脑上只需要安装客户端即可,就可以完成对SVN的管理及下载代码等。
      比如我这里将我的SVN服务器搭建在虚拟机内(相当于一个局域网SVN服务器),然后用我的电脑来访问。
      我下面以一个项目的开发来说明SVN客户端的使用。
      1.首先在SVN版本库里创建一个项目
      ①右键TortosieSVN -> Repo-browser
      ②仓库地址:svn://localhost/svn/repo
      
      ③这里用admin登录进去创建一个项目
      
      如果你之前勾选了"Save authentication",你是直接进入的;如果你要换一个账号,需要先清空缓存:
      右键TortosieSVN -> Settings
      
      ④trunk是我们的主开发目录,在trunk上右键 Create folder -> 输入文件夹名称 -> 输入日志信息
      
      2.在你的电脑的hosts文件中添加域名的对应的IP,这样就可以以域名的方式访问SVN了。
       
      3.在电脑上访问SVN(如果没有安装客户端,需要安装,开发电脑上只需安装客户端即可),将lyyzoo-scm下到本地:
      我这里在D盘建了两个目录bojiangzhou和chiangchou表示两个开发者使用的目录。下面演示在bojiangzhou目录检出项目,chiangchou目录就不赘述了。
      1.右键 -> SVN Checkout  -> 输入项目路径,以及检出目录 -> 然后输入用户名和密码 -> 检出成功
      
      
      
      或者说,你可以右键 -> TortosieSVN -> Repo-browser 登录客户端,在项目上右键 -> Checkout
      
      4.在chiangchou目录根据上面的步奏检出lyyzoo-scm项目,记得切换chiangchou用户。
      
      5.在bojiangzhou/lyyzoo-scm下按照maven的结构创建项目,可以先不用管maven。下面的是我的目录结构
      
      
     6.下面就需要先提交这个目录结构,以便大家一起开发
      ①先将增加的文件添加到本地svn(即.svn)的版本管理中。
      
      ②然后选择子文件夹
      
      ③然后可以看到src前面的标志变为蓝色加号了,说明这个文件已被加入.svn管理了
      
      ④提交文件(SVN Commit) -> 记得写上你这次提交文件的备注 -> 提交完后src前的标志变为绿色勾,表示已经和服务端SVN同步了,然后你可以在SVN上看到你提交的文件
      
      
      
      
     
     7.chiangchou用户更新项目,用chiangchou用户登录。这样我就把别人提交的文件更新下来了。
      
      
      8.新增几个文件:chiangchou用户添加了两个实体类,然后添加到.svn管理。
      
      然后你可以看到entity及其上级文件夹的标志变为了红色感叹号:
      
      提交这两个文件:提交之后就变回绿色勾了。
      
      从SVN上可以看到最近谁更新了文件,以及提交的日志日期等
      
      右键 -> TortoiseSVN -> Show log 查看最近提交的日志记录以及提交了哪些文件
      
    五、SVN客户端使用 -- 冲突解决(重点)
      两个开发人员对同一个文件进行修改,彼此代码出现覆盖的情况就称为冲突。在较短的时间内,两个程序员对同一个文件同一处代码开发,后上传的会覆盖先上传的。
      1.首先看一下修改不同处代码的冲突  
      ①下面对User.java进行修改,可以看到bojiangzhou和chiangchou的User.java的版本号都是11。以及User.java该版本的代码如下
      
      
      
      
      ②首先chiangchou修改代码如下:这里先不提交
      
      ③然后bojiangzhou修改代码如下:不在同一处,相当于两个开发人员同时修改同一个文件
      
      ④这时候chiangchou提交文件:版本变为12了。
      
      ⑤bojiangzhou再提交:可以看到是禁止提交的,原因是本地的版本已经过时了,不是最新的。
      
      ⑥需要你先更新到最新版再进行提交。因为这里没有对同一处代码进行开发,所以不会产生代码冲突,可以直接更新,代码会合并(Merge)到你的文件里。
       这时候你再提交代码即可。可以看到版本已经到13了。
        
      2.再看如果改到同一处代码的情况
      ①首先确认两个的版本都是13.
      
      
      ②chiangchou修改User.java,setPassword()方法,暂时不提交
      
      ③同时,bojiangzhou修改setPassword方法
      
      ④chiangchou用户提交文件:版本14。
      
      ⑤bojiangzhou提交文件,这时bojiangzhou的文件还是13的版本号。同样,提交失败,提示文件过时。
      
      ⑥这时再更新的话,就有代码冲突了:一是User.java文件前面的标志变为黄色感叹号了;二是提示冲突,多了几个文件。
      User.java.mine表示自己的文件(相当于备份);r13、r14则是两个版本的代码,你可以用记事本打开看到里面的代码。
      
      然后再看看冲突的User.java,变成了下面这样:可以看到冲突的两个代码。
      
      ⑦那么如何解决这个冲突呢:
      首先需要明确你的代码是否有必要覆盖别人的代码,如果不需要覆盖,那么直接撤销(Revert)所有更改,保持跟服务器的一样即可,相当于就不要你的代码了。更新后你的版本就是14了。
      
      但如果你觉得你的代码比他的好,跟另一个开发人员商量下,然后覆盖他的代码。记得先将自己的代码备份。
      这里因为你已经更新了代码,所以先将代码Revert,与服务器的版本保持一致;然后再从你备份的代码中拷贝你改动的那些代码进去。
      Revert之后,多余的文件也自动删掉了。此时你的版本就是14了。
      
      再改动代码后,提交文件。这是你的版本就是15了。同时chiangchou也要记得更新文件,chiangchou看到的代码就是bojiangzhou最新提交的了。
      
      冲突解决:上锁
      还可以通过上锁的方式避免冲突,如果你当前正在修改这个文件,又不想让别人来编辑这个文件,就给这个文件加一把锁这样其它人就不能修改了。
      不过公司里团队开发一般不会这样干,大家协作开发,在更新文件和提交文件的时候自己注意下就好了。
      ①比如我即将修改Log.java,Get lock加锁。
      
      ②输入备注
      
      ③用chiangchou账号去修改Log.java,然后提交文件,则无法提交。
      
      ④这时就需要你释放这把锁,其它用户才能提交了。
      
     冲突总结:
      冲突产生的原因:提交程序文件,本地版本号小于服务器版本号。
      冲突解决:
        ①令牌方式:给每个文件设置令牌,谁获得令牌谁有权利开发该文件。vss源代码控制管理软件使用该方式。
        ②通过版本号进行控制:用户commit文件,本地文件版本必须与仓库版本号一致才可以提交,否则禁止提交。
          本地与服务器版本号不一致,一定是本地的版本号小于服务器的。SVN就是通过版本号解决冲突。
      所以在平时的开发中,首先你需要时刻将代码更新到最新的版本,再写代码;然后提交代码前先更新下代码。
      其次,就算发生冲突,不能随意覆盖别人的代码,先商量下,有时候你覆盖了别人的代码,很容易出问题而长时间找不到原因。
     再说一下文件前面的标志:
       ①蓝色问号:新建的一个文件,本地.svn和远程仓库都没有该文件的记录
       ②蓝色加号:本地的.svn对该文件形成管理
       ③绿色勾号:本地文件、.svn管理的版本文件、远程仓库 三者一致
         ④红色叹号:本地文件与.svn和仓库的文件不一致,即用户修改了该文件
       ⑤黄色叹号:表示该文件正处于冲突状态 
     
    六、在IntelliJ IDEA中使用SVN
      看到这里,如果你细心的话,发现上面演示冲突的时候有些代码是错的,请不要太在意,用记事本写的,有些没注意到。在开发工具中就体现出来了。
      因为我平时使用IntelliJ IDEA做开发,这里简单讲一下如何在IDEA中使用SVN。
     1.在IDEA中配置SVN,Ctrl+Alt+S快捷键打开IDEA的设置或者File -> Settings;设置你的svn的路径
      
      2.导入项目就不说了,File -> Open,会自动变为idea项目。我这里已经将User.java里面的错误改正过来了;然后添加了maven管理(pom.xml)和一个配置文件。
       我导入的是bojiangzhou目录下的项目。
      3.记得在开发前先更新下你的代码,更新代码点击工具类的蓝色按钮(或者你配置的快捷键)
      
      要求输入密码:
      
      4.新建文件,添加.svn管理,会自动将新建的文件添加到.svn管理中。
      
      5.提交文件:点击绿色的按钮 -> 勾选你要提交的文件 -> 写上备注 -> 提交
      
      6.我重开一个IDEA打开chiangchou目录下的项目,用chiangchou登录,并更新代码
      7.如果不需要提交的代码可以将其放到另一个目录下,我这里改了UserController和config.properties,config.properties是针对我本地的配置,所以不希望提交上去。
      提交的时候先去掉你不提交的文件;
      
      然后会弹出这个:加入到另外一个不提交的文件夹,点击Yes
      
      然后你需要新建一个文件夹
      
      然后你就可以在Version Control(快捷键Alt+9)的Local Changes中看到NO这个目录,以后不需要提交的文件都可以放到这个目录;Default是你修改的文件默认存放的目录。
      你也可以直接在这里右键新建目录,而不用上面的方法;然后把文件移动到那个目录即可。
      
      8.可以在Version Control的Repository中看到提交的日志、版本、开发人员等
      
      9.解决冲突,这里讲下代码冲突
      ①可以看到最新的版本是20,chiangchou先改了代码,但还没提交:
      
      ② bojiangzhou先更新代码之后改了同一处的代码。这次,bojiangzhou先提交代码,让chiangchou的代码冲突....
       
      ③换chiangchou登录,更新代码,冲突:
      
      你如果点了Close,就会看到跟之前一样的东西了。
      
      ④解决的方式  
      一是你可以选择Merge,合并代码,你可以选择哪些代码需要保留,哪些不需要。不过一般不建议这样做,很容易遗漏。
      左边的是你的代码,中间的是合并后的代码,右边是服务端的最新代码。然后可以点中间的 x 去掉这段代码,或者 》 保留这段代码。
      
      然后就是,建议直接点击Accept Theirs,相当于Revert到服务端;如果你点击Accept Yours,则你的代码就覆盖了别人的代码。除非你十分确定,否则不能这样干...
      
      Revert按钮,撤销所有改动,直接与服务器保存一样。如果冲突了,记得把多余的文件手动删除。
      
      10.查看项目的所有提交记录,这个是SVN的记录;如果你想看你本地的,IDEA是记录了你的文件的每一次的变更记录的,可以看Local History,这个就不在这里说了。
      
      然后你可以根据这些历史记录对比现在的代码,想要找回以前的代码也是很简单的了,就自己试试吧。
      
      
      IDEA中使用SVN就说到这里了!!
     
    七、分支、合并、切换
      1.首先了解下SVN的目录结构:
      branches:存放支线副本:当项目稳定以后,先发布到 tags 下,如果发现了 bug,再从 tags 下检出到 branches下。在该版本下进行 bug的修复,把修复完毕的稳定的版本重新发布到 tags下。
      tags:存放标签副本,也就是存放稳定版本
      trunk:存放开发的主线,团队成员在开发的时候一直要用这个库中的内容
      
      2.假设我们的lyyzoo-scm第一个版本已经开发完了,版本号为1.0吧。现在来发布到tags
      ①我现在使用运维人员的账号登录,将整个库检出到运维人员的电脑上。
      
         
      ②进入到trunk目录,在lyyzoo-scm上右键 -> TortoiseSVN -> Branch/tag 
       
      ③点击右边的选择tags目录,然后输入/lyyzoo-scm-1.0,因为这里是拷贝lyyzoo-scm目录下的文件。然后点击OK
      
      ④然后在tags目录下更新下,就可以看到发布的1.0版本了
      
      3.上面已经发布了第一个版本,现在trunk下开发的版本属于2.0的;然后发现了1.0的一个bug需要修复下,现在将tags下的lyyzoo-scm-1.0做一个分支出来,再修复bug。
      不能直接将tags目录下的lyyzoo-scm-1.0检出进行修改,tags目录是不能用于开发的。
      ①到tags目录下,将lyyzoo-scm-1.0做一个分支到branches目录下;跟上述同样的操作。
       
      ②开发人员检出lyyzoo-scm-1.0-fix-1.0进行bug修复,并提交代码。
      
      ③然后对分支进行发布,发布到tags/lyyzoo-scm-1.1。然后更新tags,看到最新发布的版本
      
      
      4.合并,把1.1版本中改动的代码合并到trunk中去
      推荐博客:SVN merge 三种方式
      ①在trunk/lyyzoo-scm/src上右键,选择Merge
      
      ②Merge a range of revisions,合并一个范围的版本。
      你可以选择你具体修改的那个文件进行合并。这里选择tags的1.1版本进行合并,然后点Next -> Merge进行合并。
      
      ③选择tags/lyyzoo-scm-1.1进行合并,点Next -> Merge合并到trunk下。
      
      ④提交合并过来的文件。注意是否有冲突产生。然后开发人员更新到最新版本。
     
    八、使用http方式访问SVN
      通过svn://svn.lyyzoo.com/svn/repo这样的方式去访问版本库,这是svn特有的方式,只能通过svn客户端访问服务端。
      如果你想通过http的方式访问(比如在浏览器里访问),如http://svn.lyyzoo.com/svn/repo,则配置起来就比较麻烦了。
      这里只说下实现方式,可自行查找资料实现。在公司开发中我们一般不用去管服务端的事情,我们只需会使用客户端即可。
      1.利用Apache配置实现http的方式访问Subversion
       推荐博客: 配置http方式访问svn服务器 
      2.如果你发现你的Apache或SVN里没有那些文件,你可以使用集成Apache的SVN: Subversion + Apache Server。不用配置,安装即可使用。
      CollabNet需要你先注册个账号,SVN是免费使用的。
      
      3.最后就是Subversion Edge了,集成Subversion + Apache + ViewVC,它集合了Subversion所需要一切资源,无需单独安装第三方软件,且更新快,具备图形操作功能,方便使用。
       
     
    九、SVN对比Git
      这里从别的地方贴过来的,原文:http://www.jianshu.com/p/96f2db36044b
    • 适用对象不同。 Git 适用于参与开源项目的开发者。 他们由于水平高,更在乎的是效率而不是易用性。Svn 则不同, 它适合普通的公司开发团队。使用起来更加容易。
    • 使用的场合不同。 Git 适用于通过Internet,有多个开发角色的单个项目开发, Svn 适合企业内部由项目经理统一协调的多个并行项目的开发。
    • 权限管理策略不同。 Git 没有严格的权限管理控制,只要有帐号,就可以导出、导入代码,甚至执行回退操作。 Svn 则有严格的权限管理, 可以按组、按个人进行针对某个子目录的权限控制。区分读、写权限。更严格的,不支持回退操作。保证代码永远可以追踪。
    • 分支( branch )的使用范围不一样。 Git 中, 你只能针对整个仓库作 branch, 而且一旦删除,便无法恢复。而 svn 中, branch 可以针对任何子目录,它本质上是一个拷贝操作。 所以,可以建立非常多、层次性的 branch, 并且,在不需要时将其删除,而以后需要时只要 checkout 老的 svn 版本就可以了。
    • 基于第三点, Git 适用于单纯的软件项目,典型的就是一些开源项目,比如 Linux 内核、 busybox 等。相反, Svn 擅长多项目管理。 比如,你可以在一个 svn 仓库中存放一个手机项目的 bsp/ 设计文档 / 文件系统/ 应用程序 / 自动化编译脚本, 或者在一个 svn 中存放 5 款手机项目的文件系统。 git 中必须建立 n ( 项目数 )* m (组件数) 个仓库。 Svn 中只需要最多 n 或者 m 个就可以了。
    • Git 使用 128 位 ID 作为版本号, 而且 checkout 时要注明是哪个 branch, 而 svn 使用一个递增的序列号作为全局唯一的版本号, 更加简明易懂。虽然可以使用 git tag 来建立一些文字化的别名,但是毕竟那只是针对特殊版本。
    • 可跟踪性,git 的典型开发过程为: 建立分支,进行开发,提交到本地 master,删除分支。这样做的后果是以前的修改细节会丢失。 而在 svn下做同样的事情,不会丢失任何细节。
    • 局部更新,局部还原。SVN由于是在每个文件夹建立一个.svn文件夹来实现管理,所以可以很简单实现局部更新或者还原。假如你只希望更新某些部分,则svn可以很好实现。同时代码写错了,同时可以很好实现局部还原,当然git也可以通过历史版本还原,但是无法简单地实现局部还原。
    --------------少年不努力,长大搞程序。欢迎关注,如有错误,恳请指正。
  • 相关阅读:
    UNIX环境高级编程——信号说明列表
    [Fiddler]如何让Fiddler可以抓取https的请求
    [Cookie] Read Cookie and Pass in headers
    [Training Video
    [Training Video
    [Training Video
    [Training Video
    [Training Video
    [Training Video
    [Training Video
  • 原文地址:https://www.cnblogs.com/oycyqr/p/8807029.html
Copyright © 2011-2022 走看看