Comments

最近打算对帝傲狮进行重构,觉得应该是时候启用版本控制工具来管理代码了。想当初为了学习这个,我还专门看了几天的《Git版本控制管理》,可是长期在公司使用clearcase,现在我连它长什么样都记不起来了-_–# 。悔恨当初做的笔记太渣,现在重新把书啃一遍那基本上又不太现实。好在这两年网上积累了好多有关的优秀资源,以下便是我这两天通过学习&使用这些网络资源而整理的git 常用命令的使用说明

git clone

  1. clone 操作将会复制一个已经存在的git仓库
  2. clone 操作会自动的创建一个名叫origin的远程连接指向原始的仓库
  3. This makes collaborating with Git fundamentally different than with SVN

git config

  1. git config user.name设置用户名
  2. git config user.email设置电子邮箱
  3. 默认情况下是对当前仓库进行设置,加上--global标签之后,则为全局设置

git add

  1. 直到运行git commit之前,git add并没有直接影响仓库
  2. git add <file>stage 单个文件的改变
  3. git add <directory>stage 整个目录的改变
  4. git add -p交互式的add

git commit

  1. 将处于stage 状态的该表保存到仓库
  2. git commit -a会将工作区的所有改变保存到仓库
  3. 除非你真的准备好了,否则git 不会强迫你与中心仓库记性交互
  4. 就像stage 空间是工作目录与代码仓库之间的缓存一样,本地仓库是开发者的代码贡献与中心仓库之间的缓存
  5. git commit --amend修改之前的commit。这将导致当前的stage区间与前一个commit的状态融合。
  6. git reset一样,git commit --amend不应该发生在发布后的<commit>上。
  7. --no-edit可以使git commit --amend使用上一次commit的注释

git status

用来显示工作区的状态

git log

  1. 该命令被用来显示commit 历史
  2. git log将使用默认格式显示,通常会输出多于一屏的内容。使用空格翻页,使用q退出。
  3. git log -n <limit>限制输出的条数
  4. git log -oneline高度抽象概括提交情况
  5. git log --stat同时呈现相关文件、相关行的信息
  6. git log --author=<pattern>搜索指定作者的commit。pattern可以是包含正则表达式的字符串
  7. git log <since>..<until>搜索两者之间的commit。since、until既可以是commitID,也可以是branchName或者是其他的reference
  8. git log <file>查看指定文件的提交情况
  9. git log --graph --decorate --oneline—graph 顾名思义,用来图形化提交状态;——decorate用来显示分支或者便签的名称;

git checkout

  1. 该命令有三种功能:检出file,检出commit,检出branch
  2. git checkout <existing-branch>更新本地仓库与<exsiting-branch>匹配,之后的操作都将记录到该分支上。检出分支后,不必担心之前的最新代码会遭到污染,任何改变如果没有commit,只存在于stage状态
  3. git checkout <commit>检出commit。会使得工作目录的所有代码变成该commit的状态(<commit>可以为commit hash或者是tag)。检出一个旧的commit,并不会造成代码丢失,开发状态将会变为detached HEAD。值得注意的是,开发应当发生在真正的分支上,否则代码融合的时候会遇到不小的麻烦。
  4. git checkout <commit> <file>检出文件。和之前的检出不同,这种检出会影响到当前工程,使得该文件的状态变为Change to be committed,若希望还原回主线状态,应使用git checkout HEAD <file>
  5. git checkout -b <new-branch>创建分支,并切换到该分支去
  6. git checkout -b <new-branch> <exsiting-branch>与上条一样,不过创建的分支是基于<existing-branch>,而不是当前分支

git revert

  1. 作为undo 操作存在
  2. 并没有删除任何commit 结点,而是将之前的结点append 到HEAD
  3. 比reset 更安全

git reset

  1. 是一个可能影响仓库安全的命令
  2. git checkout一样,根据目的不同,有多种用法
  3. git reset <file>清除该文件的stage状态,保留工作区间的文件状态
  4. git reset将stage恢复到最近一次提交,保留工作区间的文件状态
  5. git reset --hard将stage和工作区间的文件都恢复到最近一次提交
  6. git reset <commit>将stage恢复到的状态,保留工作区间的状态,以便re-commit的时候有一个更干净的stage
  7. git reset --hard <commit>将stage和工作区间的文件恢复到状态
  8. 需要注意的是:如果之后的仓库被发布过,那么你不应该使用git reset --hard <commit>,因为有可能其他开发者对这个<commit>及之后的代码有依赖

git clean

  1. 该命令通常和git reset --hard一起使用
  2. 主要目的是用来删除工作区间里没有被追踪的文件
  3. git clean -n并不会真正执行清除,而是告诉你将会清除哪里文件
  4. git clean -f将会清理当前文件夹下的未被跟踪的文件,但并不会清理文件夹以及.gitignore中提及的文件
  5. git clean -df清理当前文件夹下的未被跟踪的文件和目录
  6. git clean -xf清理当前文件夹下的未被跟踪的文件以及那些git 通常忽略的文件

git branch

  1. 每一个branch都可以看做是独立的开发流水线,是上述所有操作组合形成的抽象引用
  2. git branch支持创建,罗列,删除以及重命名操作,通常需要配合git checkout进行分支切换,配合git merge进行代码融合
  3. 分支不仅可以使开发任务并行,还可以保证主线代码永远处于可用状态
  4. git branch罗列当前仓库中所有的分支,带上-r可以罗列远程分支
  5. git branch <branch-name>创建分支,但并没有切换过去
  6. git branch -d <branch-name>如果代码已经merge回主线,则安全的删除该分支,否则给予警告,且不执行删除操作
  7. git branch -D <branch-name>强行删除分支
  8. git branch -m <branch-name>修改当前分支的名字

git merge

  1. 通常来说merge 有两种算法来执行:fast-foward merge以及3-way merge
  2. 当前分支与目标分支之间是linear path,则执行fast-forwad merge,如图1所示,git 只需要将当前分支的HEAD移过来即可(不走回头路)
  3. 如果当前分支与目标分支之间有分叉,如图2所示,则执行3-way merge
  4. git 使用edit/stage/commit的工作流程来解决merge 冲突:使用edit来解决冲突,使用add 来闭合修改,使用commit 来完成merge

git rebase

  1. git rebase <base>将当前分支rebase为<base>,其中<base>可以为commit、tag或者是分支名称
  2. 使用rebase主要目的是保持项目仓库的linear状态,以便分支融合的时候可以使用fast-forward merge
  3. git reset一样,不要对以发布的仓库部分执行rebase
  4. git rebase -i以交互的形式进行rebase

git remote

  1. 该命令可以让你创建、查看、删除与其他仓库的连接,这些连接更像是一个个书签
  2. git remote呈现你的所有连接
  3. git remote -v和上一条命令一样,但是要多显示URL
  4. git remote add <name> <url>创建一个连接,在此之后,可以直接使用<name>来访问这个连接了
  5. git remote rm <name>删除这个连接
  6. git remote rename <old-name> <new-name>修改连接名称

git fetch

  1. git fetch <remote>将该连接的所有分支全部导入本地
  2. git fetch <remote> <branch>仅导入该连接的特定分支
  3. 我们可以checkout 远程分支,但此刻会处于一个HEAD detached状态;可以想象这些远程分支为只读的,我们能做的是review他们的代码以及merge到我们的本地分支上来

git pull

  1. git pull <remote>将该连接的当前分支导入本地,并进行融合操作
  2. git pull --rebase <remote>和上述操作效果一样,但使用rebase而不是融合
  3. git pull与SVN的update类似,作用都是保持本地代码最新
  4. --rebase可以避免不要的merge操作
  5. 使用git config --global branch.autosetuprebase always将pull的默认动作设置为rebase

git push

  1. git push <remote> <branch>推送到远程仓库去。如果本地仓库和远程仓库之间的代码不能执行fast-forward merge,则git 会拒绝该次推送
  2. git push <remote> --force和上一条效果一样,只不过会强制执行
  3. git push <remote> --tags将本地标签全部推送到远程仓库去

参考资料

附图

  • 图1 a fast-forward merge

fast-forward merge 示意图

  • 图2 a 3-way merge

3-way merge 示意图

Comments

使用无线调试对于我来讲,只有一个理由:爱惜手机电池。长时间的调试过程,使得我们的爱机必须通过USB 与电脑相连。长此以往,手机电池就会变得非常不经用。

很早之前,以为只有获得ROOT 权限的手机才能开启这个功能,直到有一天被我发现statckoverflow 上的一个帖子。(之所以会有这个错觉,是因为看到Google Play上提供的相关APP 都有root权限的声明)。那么,这里我就分别总结一下,不同情况下该如何使用无线adb

如果手机拥有ROOT 权限

在shell 里执行以下命令:

开启adb无线调试
1
2
3
4
su
setprop service.adb.tcp.port 5555
stop adbd
start adbd

这也是大部分完成无线调试APP的核心基础:在应用内使用Process 对象来执行这些命令。其中start/stop adbd,你可以通过手动开启/关闭调试模式来完成同样的目的。如果希望回到usb 模式,则应该将tcp.port修改回-1。

如果手机没有ROOT 权限

  • 事情并没有因为少一个权限而变得麻烦
  • 首先将手机通过USB连接到PC
  • 在命令行中执行adb tcpip 5555,即可开启无线adb了
  • 想要恢复有线adb时,在保持手机与PC连接的前提下,命令行中执行adb usb即可

连接与断开手机

  • 开启无线adb后,想要通过WIFI连接手机,请先确保电脑和手机在同一网段
  • 连接:adb connect android-device-ip
  • 终止:adb disconnect
Comments

Android 组件具有天生的跨进程特性,因此,android 应用开发者通常是不需要关注进程概念的。但这也往往导致我们忽视了进程的一些细节问题。这里,就目前的认识做一些小结。

Android 是以进程对用户的重要性为依据来管理进程的。其重要性分为5个层级,重要性越低的进程越容易被系统干掉。

  • Foreground process
  • Visible process
  • Service process
  • Background process
  • Empty process

Foreground process

优先级最高,即使在系统内存吃紧的情况下不到万不得已,是不会杀这类进程的。如果这类进程被杀,通常是因为用户界面卡得不能动弹而被迫执行的。这类进程所包含的组件通常满足以下特征:

1.  activity 正在与用户进行交互
2.  service 绑定的activity 正在与用户交互
3.  service 执行了`startForeground()`
4.  service 正在执行生命周期回调函数
5.  BroadcastReceiver 正在执行`onReceived()`

Visible process

优先级次之,系统在保证Foreground process 的前提下,保证这类进程的运行。这类进程虽不直接与用户交互,但用户能在界面上看到与之相关的组件。这些组件通常会有以下特征:

1.  activity 在Paused 状态,处于可视但不可交互的状态
2.  service 绑定的activity 处于paused 状态

Service process

虽然没有与用户直接交互,但它们所做做的事情与用户息息相关。所以系统会按照优先级,在保留上述进程的前提下,尽可能的保留此类进程。不符合上面描述的Service 进程都属于Service Process。

Background process

随时会被系统回收。为了提升用户体验,系统使用LRU 缓存维护这类进程,使得用户最近使用的进程推迟回收。这类进程通常只持有不可视组件,如paused 状态下的activity。

Empty process

这类进程的存在仅仅只是为了让启动进程看起来更快一些,也因此更容易被系统回收。

android:multiprocess 属性

默认情况下,该设置为false,表示该组件会在定义组件的应用进程中运行。当第三方应用调用该组件时,会有2个进程启动:第三方应用以及定义组件的应用。

如果该属性设置为true,表示允许该组件“嫁”出去:当第三方应用调用该组件时,会直接在该进程中构造组件。这么做会让组件在整个系统中的数量增加,但与调用者之间的交互更为紧密。值得一提的是,在实际开发中,这么做需要考虑并发的复杂性。

零散的知识点

  • 一个进程如果包含多个组件,那么,该进程取组件中优先级最高的作为自己的优先级
  • 一个进程的优先级会因为其他进程的依赖而提升
  • 由于service 比后台进程优先级高,一些长时间操作在service 中运行更有安全感
  • IBinder、 ContentProvider 的方法通常要注意线程安全

参考资料