【翻译】Git介绍
Git版本控制系统(VCS)快速成为Android应用程序开发以及常规的软件编程领域内的事实标准。有别于需要中心服务器支持的早期版本控制系统,Git是分步式的,这意味着每一个版本库副本都记录了项目的整个历史,并且项目贡献者不享有特权。因Linux成名的Linux之父林纳斯.托瓦兹,为了方便管理Linux操作系统的开发工作而开发了Git。就像开源运动本身,Git鼓励合作,不按等级划分。
尽管Git为命令行窗口提供了多种功能,本章主要集中探讨如何在Android Studio中使用Git。支撑Android Studio的IntelliJ平台多年来为包括Git在内的数种VCS系统提供了出色的支持。
而且不同支撑系统具有的兼容性也使得新手以及行家都能轻而易举地精通它。然而,在Android Studio中使用Git与在命令行窗口中使用Git是不同的,了解这一点非常重要。本章将向你详解在Android Studio上学习git的一切细节。通过在前面几章中学习Reminders应用程序,你学习了committ、branch、push和fetch等重要命令的基础知识,现在请重新启动这个应用程序。接着你需要使用本地及远程版本库,了解如何在协作环境下使用Git和Android Studio。
打开你在第一章中创建的Hello World项目。如果你跳过了那一章,那么新建一个项目,并把它命名为 HelloWorld。在向导界面中进行下一步的时候,一律使用默认设置。通过这个项目,了解在Android Studio上安装Git的基本原理。
【翻译】安装Git
想要使用Git,先安装它。单击操作系统上的下载按钮,如图7-1所示。
Figure 7-1. Git download page
【翻译】图7-1 Git下载页面
【翻译】在Windows操作系统中,我们建议你把Git安装在C:\java\directory文件夹中。在Mac或Linux操作系统中,你则需把Git安装在~/java文件夹中。但是无论你在哪里安装Git,确保那儿有足够的存储空间。比如说,不要把Git安装在C:\Program Files上, 因为Program和Files之间有一个空格。像Git这样以命令行为导向的工具,如果安装目录的名字中有空格,它们的文件目录很可能会出故障。一旦安装结束,必须确保 C:\java\git\bin\文件夹是你PATH环境变量的一部分。如需了解PATH PATH环境变量中添加一个路径的详细说明,详见第一章。
点击Git Bash图标,启动Git Bash终端。如果你使用的是Mac或Linux,打开终端即可。把你的名字和邮箱记到Git上,这样你的提交中才能显示相应的发起人。在Git Bash上输入下列命令,把John Doe以及以它命名的邮箱替换成你自己的。请看图7-2 中的示例图。
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
【翻译】图7-2 在Git上添加你的名字和邮箱
【翻译】回到Android Studio,继续安装Git。找到File ➤ Settings,然后在左窗格中的版本控制部分下方找到Git。点击ellipsis按钮,找到你刚刚安装的Git二进制文件(Git Binary)。为确保你的Git环境能正常运行,点击Test按钮来进行测试。接着你会看到一个显示Git及你刚安装的那个Git版本成功运行的弹出菜单。
前往VCS ➤ Import into Version Control ➤Create Git Repository。当对话框提示你勾选新建Git版本库所在的文件夹时,确保勾选HelloWorld项目的根目录文件夹。你也可以点击chooser对话框中的little Android Studio图标,这个图标可以链接到HelloWorld项目的根目录文件夹,如图7-3所示。点击确定按钮,你的Git本地版本库就被创建好了。
Figure 7-3. Selecting the directory for your Git repository
【翻译】图7-3 为你的Git版本库选择文件夹
You will notice that most of the file names in your Project tool window have turned brown. This means that these files are recognized by Git locally but are not being tracked by Git and not scheduled to be added. Git manages commits in a two-stage approach (which is different from the approach used by other VCS tools such as Subversion and Perforce).
The staging area is where Git organizes changes prior to a commit. The differences between the changes in progress, the staging area changes, and the committed changes are significant and can overwhelm new users. As a result, Android Studio does not expose these differences. Instead you get one simple changes interface that allows you to manage modified files and commit them with ease.
【翻译】你会注意到项目工具窗口上的大部分文件名都变成了棕色,这就意味着这些文件在本地中被Git识别,但是不被它追踪或添加至计划列表。不同于Subversion和Perforce等其他VCS工具的使用方法,Git分两个阶段完成提交。
暂存区是提交之前Git进行更改的区域。因为项目进行区的更改、暂存区的更改与提交后的更改都是不同的,而且这些不同会让新手们不知所措,所以, Android Studio并不显示这些不同点。反而,你会看到一个相当简洁的更改界面,它能让你管理并轻松提交被修改好的文档。
Ignoring Files
When you create the local repository, Android Studio generates special .gitignore files that prevent certain paths from being tracked. Unless you specify otherwise, Git will continue to track all the files in this directory and its subdirectories. However, .gitignore files can tell Git to ignore certain files or entire directories.
Typically, you will have one .gitingorefile for the root directory, and one .gitignorefile for each project. In HelloWorld, one .gitignoreis located in the root of HelloWorld, and one
.gitignoreis located in the root of the appfolder. Open the .gitignorefile located in the root of HelloWorld and inspect its contents. Figure 7-4 illustrates the generated .gitignorefile in the
project’s root directory. By default, Android Studio sets certain files to be excluded from your Git repository. The list includes files that are either generated by the project build or control settings specific to your local machine. For instance, the /.idea/workspace.xmlfile controls settings
for your local configuration of Android Studio. Though it is possible to track this in Git, it is not necessarily a part of the project you are building and may in fact pose a problem because this file is unique to every workspace e.g. computer. Notice that one of the entries in .gitignoreis
/local.properties. Like workspace.xml, local.properties is unique to every computer.
Pay attention to the /build entry in the list. Gradle, the Android Studio build system covered in depth in Chapter 13, places all of its output here as you compile and run your project.
Because this folder will contain everything from .class files to .dex files to the final installable
Android package, and because its contents are constantly changing, it makes little sense to track it with Git. Find the local.properties file in the Project tool window. You will notice that it’s black, whereas the other files are brown.
【翻译】忽略文件
当你创建本地仓库时,Android Studio会生成一个特殊的、可以预防某些路径被追踪的.gitignore文件夹。除非你专门说明, 否则Git会持续追踪这个文件夹及其子文件夹内所有的文件。不过 .gitignore 文件夹能够命令Git忽略某些文件及文件夹。
一般来讲,根目录文件夹中会有一个.gitignore文件,每个项目中也有一个 .gitignore文件。在HelloWorld中,一个gitignore文件位于HelloWorld根目录中,另一个gitignore文件位于app文件夹中。打开位于 HelloWorld根目录中的.gitignore文件,检查它的内容。图7-4 举例说明在项目根目录中生成的.gitignore文件。
默认情况下, Android Studio会限制某类文件进入Git版本库,这类文件既有创建项目时生成的文件,也有专属于你本地计算机上的控制设定文件。比如说,Android Studio本地配置时需要的/.idea/workspace.xml文件就属于此类。
Android Studio本地配置中。虽然你可以在Git上追踪这个控制设定文件,但它并不一定是你在建项目的一部分。事实上,它还可能造成问题,因为每台电脑的控制设定文件都是不同的。注意.gitignore文件中的一项条目就是/local.properties文件。就像workspace.xml,每台电脑的local.properties文件也都是不同的。
留意列表中的/build条目。在第13章被详细介绍的Android Studio build系统Gradle, 在你编译和运行项目时,会在此处显示它所有的输出结果。
因为这个文件夹会包含.class文件、 .dex 文件以及你最终可安装的安卓文件包上的一切东西,也因为这个文件夹内的内容时刻在改变,所以在Git上追踪它几乎没有意义。找到在项目工具窗口中的local.properties文件,你会注意到它的文件名颜色是黑色的,有别于其他棕色的文件。
Figure 7-4. The root .gitignore file contents
【翻译】图7-4 root .gitignore文件内容
Android Studio uses a color scheme that allows you to easily identify what your version control system will see as you work. As we’ve already stated, brown indicates that a a file is recognized by Git locally but is not being tracked by Git, and is not scheduled to be added. Blue indicates a file that is being tracked by Git and has been changed. Green is used for brand-new files that are being tracked by Git. Black indicates files that either have not been changed or are not being tracked. Android Studio constantly keeps track of files that are added to your project and prompts you as necessary to keep these files in sync with Git.
【翻译】Android Studio的配色方案能让你轻易查清你的VCS追踪过的工作记录。棕色文件名暗示这个文件被当地Git识别但未被追踪,也未被添加到追踪计划中,这我们之前提过。蓝色文件名暗示这个文件正在被Git追踪,而且已被Git更改。绿色文件名则用于正在被Git追踪的新建文件。黑色意味着这个文件要么还没有被更改,要么正未被Git追踪。Android Studio不停地追踪被添加到你项目中的文件,并提示你有必要通过Git来同步这些文件。
Adding Files
Open the Changes view at the bottom of the screen. It includes two sections: Default and Unversioned Files. The Default section, initially empty, represents the active changelist. As you modify and create files, they will fall under this section, because it holds files that are ready to be committed to your VCS. The Unversioned Files section contains everything that is not being tracked by VCS.
Because all of the project files are not yet tracked, they fall under the Unversioned Files section. You will want to add these to your repository. On the left side of the Changes view are two columns of icons. In the right column, click the third icon from the top (a folder icon); see the circled icon in Figure 7-5. This is a toggle that enables you to group files by folder
to better understand their relative location within your project. Right-click the Unversioned Files section header and click Add to VCS from the context menu to add these files to the Git index. Alternatively, you can click and drag the entire section to the bold Default section.
【翻译】添加文件
打开界面底部的更改视图。它包含两个部分:default和unversioned文件。最初为空白文件的default,代表可运行的变更表。当你修改并创建文件时,他们这些文件会被自动归入default部分,因为它保留那些即将被提交到VCS系统中的文件。unversioned文件包含所有不被vcs追踪的文件。
因为所有的项目文件还未被追踪,所以它们会被归入到unversioned文件中。你需要把这些文件添加到你的版本库中。更改视图的左边是两栏图标,在右栏,从顶部(一个文件夹图标)点击第三个图标。在图7-5中查看被圈出的图标。这个图标是一个切换键,它允许你按文件夹来对文件进行分组
以让你更好地了解它们在你项目内的相对位置。右击Unversioned文件的标头,接着在内容菜单键中点击Add to VCS以把这些文件添加到Git索引中。或者,你也可以点击并拖动整个文件到bold default部分。
Figure 7-5. Group files by folders
【翻译】图7-5 按文件夹对文件进行分组
After adding all the files, click the VCS icon with the green arrow pointing upward. This opens the familiar Commit dialog box you began using in Chapter 5. Click Commit to record your changes, and the Default section will eventually empty out. You can also press Ctrl+K | Cmd+K to perform the same action. From this point on, each file you touch while in Android Studio will be tracked under Git.
【翻译】添加完所有文件后, 用向上指的绿色箭头点击VCS图标,这样你就打开了你在第5章中了解使用过的提交对话框。单击Commit以记录你的更改,最终清空默认文件。你也可以按住Ctrl+K | Cmd+K来进行同样的操作。从现在起,你在Android Studio中操作过的每一个文件都可以被Git追踪了。
Cloning the Reference App: Reminders
This section extends the Reminders app that you created in Chapters 5 and 6. We invite you to clone this project using Git in order to follow along, though you will be recreating this project with a new Git repository based forked from the repostory used in Chapters 5 and 6. If you do not have Git installed on your computer, see Chapter 7. Open a Git-bash session in Windows (or a terminal in Mac or Linux) and navigate to C:\androidBook\reference\ (If you do not have a reference directory, create one. On Mac navigate to /your-labs-parent-dir/reference/) and issue the following git command: git clone https://bitbucket.org/csgerber/reminders-git.git RemindersGit. You will use Git features to modify the project as if you were working on a team.
Through the process, you will learn how to fork and clone a project, and set-up and maintain branches as you develop features. Before beginning this exercise, rename the Reminders project you completed in chapter 6 to RemindersChapter6 because you will be recreating this folder shortly. In windows you can right click the folder in Explorer and choose rename. On Linux or Mac run the following command: mv ~/androidBook/Reminders ~/androidBook/ RemindersChapter6.
【翻译】克隆Reference App: Reminders
本节将继续讲解你在第5和第6章中创建的Reminders app.为了紧跟我们的讲解步骤,建议你使用Git来克隆这个项目,尽管你会一直用一个基于fork分支的、在第5和第6章中使用的新建Git版本库来创建这个项目。如果你的电脑上没有安装Git,请看第7章。打开Windows中的Git-bash会话,(在Mac或Linux系统中,打开Terminal)前往C:\androidBook\reference\ 文件夹。(如果你还没有reference文件夹,新建一个。)在Mac系统中,前往/your-labs-parent-dir/reference/)文件夹并输入下列Git命令: git clone RemindersGit.https://bitbucket.org/csgerber ... sGit.如果你是在团队中工作,你可以用Git功能去修改这个下项目。
通过这个步骤, 你不仅能学会如何对一个项目进行分支和克隆,你还可以学习如何在开发功能时设置和保留分支。在开始练习前, 重命名你在第6章完成的Reminders项目为RemindersChapter6,因为你马上就要开始重新创建这个文件夹。在Windows中,你可以右击Explorer中的文件夹并选择重命名。在Linux或Mac上,运行下列命令:mv ~/androidBook/Reminders ~/androidBook/ RemindersChapter6.
Forking and Cloning
Forking a remote repository involves making a clone from one remote account/partition to another remote account/partition on a single web-hosting service. Fork is not a Git
command; it is an operation of a web-hosting service such as Bitbucket or GitHub. As far as we know, the two more popular web-hosting services, Bitbucket and GitHub, do not allow forks between their servers. Forking a project is the process of copying a project from its original remote repository to your own remote Git repository for the sake of changing it or making derivative work.
Historically, forking had a somewhat negative connotation, because it was often the result of different end goals or disagreements among project members. These differences often resulted in alternate versions of seemingly identical software from multiple groups, and no clear official version that the user community could rely on. These days, however, forking is strongly encouraged thanks to Git. Forking is now a natural part of collaboration. Many open source projects use forks as a means of improving the overall source base. Members encourage others to fork and make improvements to the code. These improvements are pulled back into the original project by means of a pull request, or an individual’s personal request to pull a bug fix or feature back into the main line. Because merging and branching are so flexible with Git, you can pull anything into your repository, from a single commit to an entire branch.
This chapter doesn’t cover the entirety of pull requests and open source collaboration but does cover the features that fuel this powerful form of collaboration. Log into your Bitbucket account and find the case studies on Bitbucket. If you do not yet have a Bitbucket account, navigate your browser to bitbucket.org and sign-up. Signing-up takes about 30 seconds.
Once you’ve logged into Bitbucket, you can find the Reminders repository by using the search box in the upper right corner of the Bitbucket web interface. In that search box, type csgerber/reminders. Again, do not confuse this with the finished reminders-git repository which you cloned earlier as a reference. To fork this project, click the Fork button along the left margin as shown in Figure 7-6. When prompted by the subsequent window, accept the defaults and click the Fork repository button as showing in Figure 7-7.
【翻译】分支和克隆
分支一个远程版本库需要把一项代码托管服务中的一个远程账户/分区克隆到另外一个远程账户/分区上。分支不是一项Git命令;
它是Bitbucket或GitHub等提供代码托管服务的平台上的一项操作。据我们所知,Bitbucket和GitHub这两类最受欢迎的代码托管服务平台,不允许用户在它们的服务器之间进行分支。分支一个项目是把远程版本库上的项目复制到你自己的远程版本库上,其目的是为了改变或拷贝这个项目。
以往, 分支会带有一些消极含义,因为它往往是项目成员的不同目标与分歧的后果。这些差异经常在多个群体内产生外表雷同的数个软件版本,而且用户群没有明晰规范的官方版本来参考。然而在现在,受益于Git,我们强烈推荐使用分支功能。分支成为合作项目中不可或缺的部分。许多开源项目都把分支视为提高整个开源基础的一种有效工具。成员们鼓励其他人通过分支来完善代码。通过提交申请(pull request)或个人针对主线的错误修正、功能恢复申请,这些改良请求得以被添加到初始项目中。因为Git中的合并和分支也是非常灵活的,所以你可以把一切东西(从单项提交到整个分支)放入你的版本库。
这一章虽没有覆盖全部的提取请求和开源合作,但包含了启动这一高效合作方式的所有功能。登陆你的Bitbucket账号,找到Bitbucket上的案例研究。如果你还没有Bitbucket账户,打开你的浏览器到bitbucket.org并注册。注册大概会花30秒。
一旦登陆到Bitbucket上, 你可以通过使用Bitbucket网页界面右上角的搜索框去寻找Reminders respository。在那个搜索框中,输入csgerber/reminders.再说一次,不要把它与你之前克隆为参照物的reminders-git版本库混肴。为了分支这个项目,点击左边空白部分的Fork按钮,如图7-6所示。当随后出现的窗口发出提示时,接受默认,点击fork repository按钮,如图 7-7所示。
Figure 7-6. Click Fork in the Reminders repository left margin controls
图7-6 单击左边空白控制器内Reminders respository中的Fork按钮
Figure 7-7. Click the Fork repository button
【翻译】图7-7 单击Fork版本库按钮
Now, we’re going to clone the repository that you just forked. In Git, cloning is the process of copying an entire Git project from another location, usually from a remote to local.
Find your fork of the project and copy the URL. You can do this by typing your-bitbucket- username/reminders in the search box of the Bitbucket web interface. Directly below the search box, along the upper-right of the Bitbucket web interface, you will find the clone box in which there will be a URL that should look something like: git@bitbucket.org:csgerber/ reminders.git or your-bitbucket-username@bitbucket.org/your-" rel="nofollow" target="_blank">https://your-bitbucket-usernam ... cket- username/reminders.git.
If you don’t have an http URL then click the button next to the URL which should be labeled SSH as seen in Figure 7-8. This will expose a dropdown allowing you to select an http URL. Navigate to VCS > Checkout from Version Control > Git. The dialog box shown in Figure 7-9 opens, prompting you for a VCS Repository URL, a Parent Directory, and a Directory Name. The VCS Repository URL is a URL from the clone box earlier, and the combination of Parent Directory and Directory Name is where you want the copy to be placed on your local computer. By default, the name of the project in the Directory Name is lower-case. We recommend you name your projects in upper-case, so please change that according to Figure 7-9.
【翻译】现在,我们要开始克隆你刚刚分支过的储存库了。在Git上,克隆是把整个Git项目从一处复制到另一处的过程,通常是从远程复制到本地。
找到你项目中的分支并复制URL.你也可以通过在Bitbucket网站界面上的搜索框中输入your-bitbucket- username/reminders来完成这一步操作。在搜索框的正下面,沿着Bitbucket网站界面的右上角,找到克隆框,在它里面会有一个URL,它看起来就像: git@bitbucket.org:csgerber/
如果你没有相应网址,点击URL边上的标签名为SSH的按钮,如图 7-8所示。页面就会显示一个允许你选择一个网址的下拉菜单。从VCS > Checkout中找到Version Control > Git,接着图7-9中显示的对话框会打开,提示你VCS版本库网址、一个根目录以及一个目录名。VCS版本库网址是来自之前克隆窗口的一个网址,至于根目录和目录名,它们在你存储复制副本到你本地电脑的目标路径上。默认情况下,目录名中的项目名称是小写字体,我们推荐你使用大写字体来命名你的项目,所以请根据图7-9来调整。
Figure 7-8. The Bitbucket Share URL
【翻译】图7-8 Bitbucket共享网址
Figure 7-9. Cloning the repository with the Git GUI
【翻译】图7-9 使用Git GUI来克隆版本库
Click Clone, and the source code will be copied locally.
【翻译】单击克隆选项,源代码就会被复制到本地
Using the Git Log
The Git log is a powerful feature that gives you the ability to explore the commit history of your project. Open the Changes tool window by clicking its tool button or pressing Alt+9 | Cmd+9 and then select the Log tab to expose the log. Figure 7-10 illustrates the history of the Reminders project through the final commit at the end of Chapter 6. This view shows the timelines associated with the individual branches in the repository.
【翻译】使用Git日志
Git日志拥有强大的功能,它能让你查看你的项目提交历史。在点击工具按钮或按住Alt+9 | Cmd+9ji键,选择日志选项卡以查看过往记录之后,打开更改工具窗。图7-10通过第6章结尾部分的最后提交说明了Reminders项目历史。这个视图显示了与版本库内个人分支有关的时间轴。
Figure 7-10. Exploring the Git log
【翻译】图7-10 查看Git日志
Clicking individual entries in the timeline reveals the files in a changelist to the right; these are the files that were changed as part of the commit. Click the files from any particular commit and press Ctrl+D | Cmd+D (or simply double-click them) to get a visual text diff, which is a side by side comparison highlighting the changes to the files. You can use the toolbar buttons above the changelist to edit the source, open the repository version of a file, or revert selected changes. You can also use the window below the log to see the committing author, date, time, and a hash code ID. These hash codes are unique IDs that can be used to identify individual commits when using some of Git’s more advanced features.
【翻译】单击时间轴中的个人键会显示右边更改列表中的文件,它们曾被更改为提交的一部分。单击任意一个提交中的文件,按住Ctrl+D | Cmd+D (或仅双击它们),你会看到一个可视化文本diff,它是并排显示比较结果,突出显示了文件的更改。你可以使用更改列表上的工具栏按钮去编辑这一资源,打开一个文件的版本库版本或者还原被选中的更改。你也可以使用日志下面的窗口去查看提交发起人、日期、时间和哈希代码标识符。这些哈希代码都是独特的标识符,它们能在你使用Git的一些高级功能时鉴别个人提交。
Branching
Until now, you’ve made all your commits on a single branch called master, which is the default branch name. However, you don’t need to remain on master. Git allows you to create as many branches as you want, and branches can serve several purposes in Git. Here’s a likely scenario. Say you’re working with a team of developers and you’ve each been assigned specific tasks during a development cycle. Some of those tasks are features and some are bug fixes. One logical way to approach this work is for each task to become a branch. The developers all agree that when a task is complete and tested, the developer will merge the task branch into a branch called dev and then delete the task branch. At the end of the development cycle, the dev branch is tested by the QA team, which either rejects the changes and kicks the project back to the development team, or signs-off on the cycle and merges dev into master. This process is called Git Flow, and it is the recommended way to develop software on a team with Git. You can read more about Git Flow here:https://guides.github.com/intr ... .html
Git Flow works great with large teams, but if you’re developing solo or working with only one or two other developers, you may want to agree on a different workflow. Whatever your workflow, the branching functionality in Git is flexible and will allow you to adapt your workflow to Git. In this section, we’ll assume you are working on a team project and have been given the task of adding a feature in the Reminders app which allows users to schedule a Reminders at particular times throughout the day.
【翻译】分支
【翻译】到现在,你已经在默认分支名为master的单个分支进行了所有提交。然而,你并不需要锁定master这一个分支上,Git允许你新建尽可能多的、有多种用途的分支。下面是一个可能出现的场景:比如说你与一组开发人员合作,你们每个人都在这个开发周期内被安排了特别的任务,这些任务中有些是关于功能的,有些是有关漏洞调试的。为了完成这项工作,为每一个任务设一个分支是一个合理的方法。开发人员一致同意当一个开发人员在完成一项任务并接着测试它时,他需要把这个任务分支合并到一个叫dev的分支上,然后删除这个任务分支。在开发末期,质检小组测试dev 分支。他们要么拒绝更改并把这个项目退回原开发团队,要么中止这个周期,把dev 分支合并到主分支中。这个被叫做 Git工作流的方法,经常被推荐给使用Git来开发软件的团队。想了解更多有关Git工作流的信息,点击这里:https://guides.github.com/intr ... .html
在大型团队中,Git工作流有极佳的应用效果。但如果你一个人或仅与一两个人合作开发,你可能需要另外的工作流。无论你的工作流是什么,Git中的分支功能都是灵活的,而且还能把你的工作流改编整合到Git上。在这一节,我们假设你是在团队中开发一个项目,你被分配的任务是在Reminders app中添加“允许用户在一天中的任何时间段编写一个提醒事项”的功能。
Developing on a Branch
Open the Reminders-Git project you cloned earlier by choosing File ➤ Import Project.Right-click the Reminders-Git root folder in the project view and choose Git ➤ Repository ➤ Branches to open the Branches prompt window. This prompt allows you to explore all the available branches. Click New Branch from the prompt. Name your branch
ScheduledReminders, as in Figure 7-11.
【翻译】在分支上开发
【翻译】选中➤Import Project文件,打开你之前克隆的Reminders-Git项目。右击项目视图中的Reminders-Git根文件夹,选择Git ➤ Repository ➤分支打开分支提示窗口。这个提示窗口允许你查看所有能查看的分支点击提示窗口中的New Branch把你的分支命名为ScheduledReminders, 如图7-11所示
Figure 7-11. Creating a new branch with Git
【翻译】图7-11 用Git创建一个新分支
The new branch will be created and checked out for you to work on. Open the Changes view and click the green plus button to create a new changelist. Name it ScheduledReminders, like your new branch, as the next round of changes will introduce the feature which schedules reminders. Make sure the Make This Changelist Active check box is selected, as shown in Figure 7-12.
Figure 7-12. Creating a new changelist for the branch work
【翻译】图7-12 为分支工作创建一个新的更改列表
To begin your new feature, you need to add a new option to the dialog box that shows when a reminder is clicked. Open RemindersActivity.java and go to the top of your onItemClick() method in the first OnItemClickListener nested class which is attached to the mListViewvariable. Add Schedule Reminder as a third entry in the String array that builds the clickable options as shown in line 92 of Figure 7-13. Next you need to allow the user to set the time for the reminder when your new option is clicked. Find the second nested OnItemClickListener that you attach to the modeListView that creates the dialog box when individual reminders are clicked. This will be after the dialog.show() method
invocation. Look inside its onItemClick() method as seen on line 101 and make the changes shown in Figure 7-13. You will need to resolve the import for the Date class.
【翻译】为了创建新功能,你需要添加一个新选项到对话框上,该框能显示reminder被点击的时间。打开RemindersActivity.java 文件夹,去你的onItemClick() method的上方,这个method在第一个附加在mListViewvariable上的OnItemClickListener嵌套类中。添加Schedule Reminder 作为 String 列阵中的第三个项目,该列阵建立了如图7-13的92行所示的可点击的选项。接下来,你需要授权用户在你的新选项被点击时为提醒事项设置时间。找到你把它附在modeListView 上的第二个nestedOnItemClickListener,用它新建当个人提醒事项被点击时出现的对话框。这会紧跟在dialog.show() method
调用后面。查看如101行所示的onItemClick() method,作出如图7-13所示的更改。你需要解决日期类信息的导入问题。
Figure 7-13. Changes for scheduled reminders
【翻译】图7-13 为scheduled reminders作出更改
Here you change the else block where the reminders are deleted to an else if block, which checks for the position at index 1. You add an else block that runs when the third new option is clicked. This block creates a new Date representing today and uses it to build a TimePickerDialog. Run the app now to test the new option. Figure 7-14 shows the new feature in action.
【翻译】把提醒事项被删除的else block更改成在索引1中检验位置的else ifblock。添加一个当第三个新建选项被点击时能运行的elseblock。这个block能新建代表“今天”的Date 文件,接着用这个block来创建一个TimePickerDialog文件。运行这个程序来测试这个新选项。图7-14 显示了操作中的新功能。
Figure 7-14. Trying the Schedule Reminder option
【翻译】图7-14 尝试Schedule Reminder选项
Now that you have part of your new feature working, press Ctrl+K | Cmd+K to commit with the message Adds new scheduled time picker option. Go back to the IDE and move the two lines that find the reminder outside of the position==0 condition. Mark the reminder variable as final. See Figure 7-15 for an example.
【翻译】既然你的部分新功已经能成功运行了,点击Ctrl+K | Cmd+K提交,记得在提交中加上Adds new scheduled time picker option。返回IDE,移动position==0condition外的能找到提醒事项的两条线。把reminder变量标记为“final”。请看图例7-15
Figure 7-15. Move the reminder variable outside the if block
【翻译】图7-15 移动if block外的reminder变量
Next go to the else block you just added where you construct and show the time picker dialog box. Add the following code just before the line that shows the dialog box corresponding to line 113 in Figure 7-13:
【翻译】接下来去你刚刚添加的elseblock,在这儿你建立并演示了time picker对话框。在显示与图7-13中的113行相一致的对话框的这一行的前方,添加下列代码:
final Date today = new Date();
TimePickerDialog.OnTimeSetListener listener = new TimePickerDialog.OnTimeSetListener() {
@Override
public void onTimeSet(TimePicker timePicker, int hour, int minute) {
Date alarm = new Date(today.getYear(), today.getMonth(), today.getDate(), hour,
minute);
scheduleReminder(alarm.getTime(), reminder.getContent());
}
};
This creates a listener for the time picker dialog box. Inside this listener, you use today’s date as the base time for your alarm. You then include the hour and minute chosen from the dialog box to create the alarm date variable for your reminder. You use both the alarm time and the reminder’s content in a new scheduleReminder() method. Android Studio will flag the TimePicker as an unresolved class and flag the scheduleReminder() method as an unresolved method. Press Alt+Enter to resolve the import for the TimePicker class. Press F2 and Alt+Enter again to open the IntelliSense dialog box and then press Enter to have Android Studio generate the method for you, as shown in Figure 7-16.
【翻译】就这样,你就为time picker对话框创建了一个listener。在listener内部,把今天的日期设为你闹钟的初始日期。然后把从对话框中选择的小时和分钟囊括进去,为你的提醒事项建立闹钟日期变量。用一种新的scheduleReminder()方法,使用闹钟时间和提醒事项内容。Android Studio会把TimePicker标记为未被解决类,把scheduleReminder()method 标记为未解决method。按住Alt+Enter来解决TimePicker类的导入问题。再次按住F2和Alt+Enter,打开IntelliSense对话框,接着按住 Enter键让Android Studio为你生成相关方法,如图7-16所示。
Figure 7-16. Generate method using IntelliSense
【翻译】图7-16 用IntelliSense生成相关方法
Choose the RemindersActivity class, as shown in Figure 7-17.
【翻译】选择RemindersActivity 类,如图 7-17所示。
Figure 7-17. Selecting the RemindersActivity as the target class
【翻译】图7-17 选择RemindersActivity作为目标类
Add the following code to the new method body:
【翻译】把下列代码添加到新的method主体上:
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); Intent alarmIntent = new Intent(this, ReminderAlarmReceiver.class); alarmIntent.putExtra(ReminderAlarmReceiver.REMINDER_TEXT, content);
PendingIntent broadcast = PendingIntent.getBroadcast(this, 0, alarmIntent, 0); alarmManager.set(AlarmManager.RTC_WAKEUP, time, broadcast);
Again, Android Studio will flag a bunch of errors for the missing imports in the code. Press F2 then Alt+Enter to open the quick fix prompt and fix each error. The quick fix option will eventually prompt you that ReminderAlarmReceiver does not exist. Press Alt+Enter and select the first option to generate the class. Press Enter on the first popup dialog to use the suggested package then press Enter again on the second popup dialog to add this new class file to Git. Make the class extend BroadcastReceiver and implement the onReceive() method. Your ReminderReceiver.java file should look like this:
【翻译】这样Android Studio会再次标记代码中的missing imports内的一系列错误。先按F2 键,接着按住Alt+Enter键,打开快速修改提示窗,修改每一个错误。快速修改选项最终会提示你ReminderAlarmReceiver不存在。按住Alt+Enter,选择第一个选项,生成类。在第一个弹出的对话中按住Enter键来使用推荐的程序包,然后在第二个弹出的对话中按住Enter键来把新建的类文件添加到Git上。把这个类扩展成BroadcastReceiver,执行onReceive()method。你的ReminderReceiver.java 文件看起来是这样的:
package com.apress.gerber.reminders;
import android.content.BroadcastReceiver; import android.content.Context;
import android.content.Intent;
public class ReminderAlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
}
}
Tip Alternate between pressing F2 (next highlighted error) and Alt+Enter (quick fix) repeatedly to have Android Studio fix many of the errors that arise as you copy the code from listings like Figure 7-16. It will add missing imports as well as offer to generate code for undefined methods, constants, and classes.
【翻译】小贴士 多次轮流按住F2键(突出显示下文的错误)和Alt+Enter键 (快速修改) ,能让Android Studio修复当你从列表中复制代码时产生的一些误差,列表如图 7-16所示。它会添加missing imports和offer来作为未定义的方法、常量和类产生代码。
Return to the RemindersActivity.java file. Find and fix the last error by Pressing F2 then Alt+Enter and select the second suggestion to code-generate a String constant, as illustrated in Figure 7-18. Set the value of this text to "REMINDER_TEXT".
【翻译】返回到RemindersActivity.java文件。按住 F2 键找到并修改最后的错误,然后再按Alt+Enter键,选择第二个提示让代码生成一个字符串常量, 如图7-18所示。把这个文本的值设置为"REMINDER_TEXT".
Figure 7-18. Generate a Constant field
【翻译】图7-18 生成一个常量域
Finally, open your AndroidManifest.xml file and add a receiver tag to define the new
BroadcastReceiver, as shown in Figure 7-19.
【翻译】最后,打开AndroidManifest.xml文件,添加一个接收标签来定义一个新的
BroadcastReceiver,如图 7-19所示
Figure 7-19. BroadcastReceiver manifest entry
【翻译】图7-19 BroadcastReceiver显示键
Run the app to test. You should be able to tap a reminder, select Schedule Reminder, and set a time for it to fire. Selecting the time will not do anything yet because we have not covered the details on BroadcastReceivers. Now press Ctrl+K | Cmd+K to invoke the Commit Changes dialog box. Take time to confirm the changes you’ve made so far in the
Commit Changes dialog box. Note that the dialog box retains the message from your prior commit, which you should update as shown in Figure 7-20.
【翻译】启动app开始测试接着你能够点击提醒设置,选择ScheduleReminder,为它设置一个运行时间。设置时间产生不了任何影响,因为我们还没有涉及BroadcastReceivers上的所有细节现在按住Ctrl+K | Cmd+K来调用命令更改对话框。花一些时间来确认你到目前为止在提交更改对话框中作的更改。
注意这个对话框保留了你之前提交的信息,如图7-20所示,你应该更新那些提交。
Figure 7-20. Git’s Commit Changes dialog box
【翻译】图7-20 Git的提交更改对话框
With the RemindersActivity selected, click the Show Diff button (shown in Figure 7-20) to bring up a side-by-side diff of all changes. Click the up- and down-arrows in the upper-left corner or press F7 to move between earlier and later differences in the file. These controls appear in Figure 7-21. Use the down-arrow to move to the interesting changes in your onItemClickListener.
【翻译】选中RemindersActivity ,点击Show Diff按钮(如图7-20所示),并排显示diff中所有的更改。点击左上角的上下箭头或者按住F7键,查看早期的文件与后期的文件的变化。这些控件会在图7-21中显示。在你的onItemClickListener上,用向下箭头找到你需要的更改。
Figure 7-21. Visual text diff view
【翻译】图7-21 可视化文本diff view
So far, you have managed to include an OnTimeSetListener, which is not currently being used. (The light gray coloring of the listener variable indicates that it is not used in code.) As you move through your code in this view, you are reminded not only of changes you have already made, but also of changes you may have missed, which gives you another chance at fixing problems prior to committing. The diff view is also an editor with some syntax-aware features. Should you choose to make minor tweaks, you can take advantage of things such as auto-complete.
Press the Escape key to dismiss the diff view, and change your commit message prior to committing the changes. Click Commit to allow Android Studio the chance to perform code analysis. You will see another dialog box telling you that some of the files contain problems. The dialog box will hint that there are warnings in the code. At this point, you can click the Review button to cancel the commit and generate a list of all potential issues. Although it is not good practice to ignore warnings, you can intentionally leave these for now and proceed with the next step.
【翻译】到现在为止,你已经成功完成了一个现在未被使用的OnTimeSetListener。(listener变量中的浅灰色暗示这个变量没有被代码使用)当你查看视图里的代码时,你不仅会被提示那些你已经完成的更改,也会被提醒那些你可能遗漏的更改,这给你额外的机会去修正提交前的问题。diff view也是一个拥有一些语法功能的编辑器,如果你想要作微小的调整,你可以利用像auto-complete这样的小设置。
按住Escape键退出diff view,改变你在提交更改之前所提交的信息。点击Commit,授权Android Studio执行代码分析,你会看到另一个对话框,它能告诉你哪些文件有问题。对话框会提示代码里的警告。就此,你可以点击review按钮,取消此次提交,生成一个列出潜在问题的列表。尽管忽视警告并不是一个好习惯,但你现在可以忽视它们,然后进行下一步。
Git Commits and Branches
The Git style of commits on branches is similar but may feel somewhat different from what you are used to if you come from a traditional VCS background using tools like Perforce or Subversion. You’ll want to understand the subtle differences in how Git manages commits and branches. These differences can confuse new-comers, but they are the core of what gives Git its power and flexibility.
Commits in Git are treated as first-class entities in the history of a project, which are identifiable by a special commit hash code. While you don’t need to understand the specifics of how Git implements individual commits and versioning, it is important to think of commits as objects or entities that exist within a history timeline that represents the entire state of the repository. A commit exists as an atomic unit of work that has occurred at one point in Git history, which is annotated with a commit message describing the work. Each commit has a parent of one or more commits that precede it. You can think of branches
as labels that point to an individual commit in history. When you create a branch, a label is created at that point in the history, and as you make commits to that branch, the label follows the history of commits. The following diagrams, starting with Figure 7-22, illustrate the Reminders project history as it is currently seen by Git.
【翻译】Git提交和分支
【翻译】如果你在是传统的VCS环境中使用像Perforce或Subversion这样的工具,git在分支上的提交方式与你之前熟悉的提交方式是相似的,但有些许差异。你可能想知道Git在处理提交和分支上的些微差异。这些差异可能会迷惑初学者,但是它们是赋予Git强大与灵活的核心要素。
Git中的提交在项目历史中被视为第一类entity,与哈希代码这一特殊提交一样。尽管你并不需要了解git执行个人提交和版本控制的细节,把提交视为存在于历史时间轴内的代表整个版本库状态的对象和entity是非常重要的。一次提交是以原子工作单元的形式存在,它发生在被描述工作情况的提交信息注解的Git历史的某一阶段。每次提交都有在他们前面的一个或多个父级提交。你可以把分支看成
指向项目历史中的一项个人提交的标签。当你创建一个分支的时候,一个标签就在项目历史中被创建。当你向分支提交的时候,这个标签会跟踪提交历史。从图7-22中开始,下面的图表列出了正在被git查看的reminders项目历史。
Figure 7-22. Git history showing ScheduledReminders branch
【翻译】图7-22 显示ScheduledReminders分支的git历史
Note Android Studio commit logs progress from bottom to top, whereas our diagrams progress from top to bottom.
【翻译】注意 Android Studio提交记录过程是是从下到上进行的,然而我们图表里显示的过程是从上到下。
The master branch is represented by the grey arrow pointing to the last commit A from the cloned project. (Comparing with the Git log view, you will note that there are other commits proceeding A, but they are left off for brevity.) The ScheduledReminders branch is the green arrow pointing to the latest in your series of commits B and C implementing the new feature. We use single letters as labels for simplicity, but Git uses commit hash codes, which include much longer hexidecimal names such as c04ee425eb5068e95c1e5758f6b36c6bb96f6938. You can refer to a particular commit by using only the first few characters of its hash so long as they are unique or not similar to the first few letters of any other hash.
【翻译】主分支是由克隆项目指向最后的提交A表示。(与Git日志视图比较,你会注意提交A之前的提交,但是出于简洁需要,它们被省略掉了。)ScheduledReminders分支是绿箭头,它指向执行新功能的、最新的提交B与提交C系列。为了简洁,我们使用单个字母作为标签。但是Git使用一个长得多的16进制的提交哈希代码,比如说c04ee425eb5068e95c1e5758f6b36c6bb96f6938这一十六进制名称。你也可以仅用哈希代码中最开始的几个数字来作为一个特殊的提交,只要他们是独特的或者这几个数字与其他哈希代码不相似。
Where is Revert?
One of the big hang-ups people have when they try Git for the first time is adjusting to Git reverts, because they do not work the way other VCS clients work. A Git revert is a commit (unit of work) that unwinds an earlier commit. The best way to understand is to see it in action. Let’s make a change that fixes your deprecation warnings in RemindersActivity. java. Introduce the Calendar object and remove the Date object, as shown in Figure 7-23.
【翻译】Revert(撤销)在哪儿?
【翻译】当人们第一次使用Git时,遇到的一大问题就是适应git撤销,因为Git中的撤销与其他版本控制系统中的撤销不一样。一项Git 撤销是可以展开之前提交的提交(工作单元)。了解它的最好方式在操作中观察它。让我们作一个更改,修正RemindersActivity. java文件夹内的错误警示。引入Calendar 对象,移除Date 对象,如图Figure 7-23所示。
Figure 7-23. Fix the deprecation warnings
【翻译】图7-23 修改错误提示
Build and run the code to verify that it works, and then commit this change with the message Fixes deprecation warnings. Note there will still be a warning for the unused variable, addressed later in the “Resolving Conflicts While Rebasing” section. The revert command in Android Studio is much different than the Git revert command. Here you will work with the command-line git revert command to understand the difference. Find the “Fixes deprecation warnings.” commit in the Git history of the Changes tool window, right click it and choose copy hash to copy the commit hash code to your system clipboard. Now open the terminal by clicking the terminal window button along the bottom margin and enter git revert and paste the commit hash as the last part of the command. Your command should look like Figure 7-24. Press enter and Git will launch a commit message edit session in your terminal as shown in Figure 7-25. Type “:q” to quit the edit session which saves the default commit message and performs the commit.
【翻译】建立并运行代码确保它能正常运行,然后用Fixes deprecation warnings这一信息来提交更改。注意在“Resolving Conflicts While Rebasing”分段内,仍然会出现有关未使用的变量及未编址的字母的警示。Android Studio中的更改命令与Git上的更改命令是大大不同的。这儿你需要用到git revert命令行命令去理解这个差异。在更改工具窗口找到Git历史记录中的“修改错误提示”提交, 右击它,选择复制哈希代码以复制提交它到你系统上的剪贴板中。现在打开终端,点击底部的终端窗口按钮,进入git revert,复制命令最后部分的提交哈希。你的命令会像图7-24。按住enter,Git会在你的终端启动一个提交信息编辑会话,如图7-25所示。.输入“:q”退出编辑会话,保存默认提交信息,执行提交。
Figure 7-24. Issuing the git revert command from the terminal
【翻译】图7-24 从终端发布Git撤销命令
Figure 7-25. Commit message edit. Exit by typing :q.
【翻译】图7-25 提交信息命令编辑输入q退出
A git revert causes a new commit is performed that unwinds the prior commit. Switch back to Android Studio and see what has changed. All of the deprecation warnings have returned with the unwound change. Your Git history will reflect the commit. Git applies
a reversal of all the changes from the prior commit and immediately performs a commit with these changes and presents an identical message from the last commit prefixed with Revert. Contrast this with other tools that track your local modifications to files and allow you to undo the modifications prior to committing. Even though this new style of backing out changes is different, Android Studio gives you an interface for doing a revert that is consistent with classic, more familiar version control tools. At the time of this writing, there is no IDE command or menu action that triggers the equivalent of a Git revert. However, a built-in option allows you to locally apply a reversed change from local history, Git history, or even a patch file. A Git revert automates the two steps of applying the reversed change and performing the commit. Figure 7-26 illustrates the Git history, with commit D introducing the change that fixes deprecation, and commit -D representing the unwound change that restores the deprecated calls to the Date object.
【翻译】git撤销造成一次新的提交,它是在解除之前提交的情况下完成的。转回Android Studio,查看什么被改变了。所有的这些错误提示都显示了unwound更改。你的Git历史将反映这次提交。Git对
之前提交中的所有更改作出还原,然后用这些更改立即执行一项提交。它与前缀为Revert的最后一项提交呈现完全相同的信息。把这个从追踪你当地修改到文件的工具与其他工具对比,然后撤销提交之前的修改。尽管这种新式更改不同于其他的更改,Android Studio给你一个界面来作撤销,它是与经典版本相容的、你更熟悉的版本控制工具。在写作这段话的时候,还没有IDE命令或菜单操作能让Git进行还原。然而,内置的选项会允许你在当地历史、Git历史甚至一个补丁文件夹中使用还原更改。Git还原会自动调整应用还原更改与执行提交两步。
图 7-26 显示了Git历史,它的提交D不仅介绍了修改错误更改,也代表了能把 deprecated calls 恢复到日期对象的unwound更改。
Figure 7-26. Git history after revert
【翻译】图7-26 还原之后的Git历史
The other way to unwind a committed change is to use the reset command, which works like revert but has a subtle difference. Add the changes from Figure 7-23 back into the source and commit them again. Your Git history will then have an extra E commit following the -D, as shown in Figure 7-27. This time Choose VCS ➤ Git ➤ Reset Head. Enter HEAD~1 in the pop-up dialog box, as shown in Figure 7-28, and click Reset.
【翻译】另外一种解开已提交更改的方式是用重置按钮,它的工作原理类似于撤销,但它们之间有细微差别。把来自图7-23 中的更改添加到源文件,然后并再次提交它们。接着然后,在-D后面,你的Git历史就会多出一个有一个多余的提交E,如图7-27所示。这次选择VCS ➤ Git ➤Reset Head.进入弹出对话框内的HEAD~1 ,如图7-28所示,点击重置。
Figure 7-27. Git history after reapplying the deprecation fix
【翻译】图7-27 重新使用错误修改之后的Git历史
Figure 7-28. The Git Reset Head dialog box
【翻译】图7-28 Git reset head重置中心对话框
Git will sync your repository to the commit prior to your last commit, which is the equivalent of an undo for that commit—making your history look as it did in Figure 7-26. Android Studio enhances the Git reset by reapplying your changes using your current changelist. This gives you a second opportunity to reclaim a commit in the case where you accidentally perform a reset. In most cases you will want to completely discard the changes after a reset. Click the revert changes button in the changes tool window to completely discard the changes. The revert changes button is circled in Figure 7-29.
【翻译】Git会同步你的版本库到你最近提交之前的那个提交上,这一步与撤销那个提交产生同样的结果,它能让你的项目历史看起来如图7-26中所示一样。Android Studio通过使用当前更改列表来加强Git重置功能。当你不小心点击重置时,它能给你第二次机会来收回那个提交。在大部分情况下,你可能想要完全放弃重置后的更改。那么点击更改工具窗口中的更改按钮,完全放弃更改。图7-29中圈出了重置更改按钮。
Figure 7-29. Click the revert changes button
【翻译】图7-29 点击重置更改按钮