Let’s reset even further to remove all traces of your work on the deprecated method calls. Choose VCS ? Git ? Reset Head. Then enter HEAD~2 in the pop-up dialog box, shown in Figure 7-28, and click Reset. Remember to click the revert changes button afterwards. This will become a habit each time you use Git Reset in android Studio. Your history will then reflect that of Figure 7-22.
【翻译】让我们进一步重置,使用deprecated method calls清除你项目工作中的所有追踪。选择VCS ? Git ?Reset Head.进入弹出对话框中的HEAD~2 ,如图7-28所示,然后点击重置。接着,记得点击重置更改按钮,把这个养成习惯,日后每当你在Android Studio中使用Git重置时,记得点击它。你的历史会在图7-22中反映出来。
【翻译】还原和重置之间的差别虽然很小,但很重要。尽管重置会撤销上次提交中的更改,还原却可以把它再添加回来。通过许多提交,还原可以备份你的分支标签。如果你无意中作了一项提交,你经常需要撤销或删除它。在这样的情况下使用重置是相当恰当的,因为它是最简单的选项,而且不会被添加到项目历史里。然而在一些情况下,你可能想要你的项目历史反映解除提交的工作。比如说,如果你从一个项目中pull一个功能并且想把这次功能清楚记录到用户社区上。还原的另一个功能是应用在远程版本库上,将在本章的后部分讨论。因为你仅仅可以添加提交到远程版本库,所以在远程版本库上删除或展开一项命令的唯一方式是使用还原功能,它能把inverted 更改添加为提交。
You’ll start by adding a new feature on the main branch for the extreme procrastinator. This new feature will set the default of all reminders to Important because we know you procrastinators will ignore anything other than the most important reminders. Click File ? VCS ? Git ? Branches to bring up a list of branches. Select the master branch and then select Checkout. Note that the underlying source has been changed, all of the changes to
support the new feature have been removed, and your project has been restored to its state before you began working on scheduled reminders. Create a new changelist entitled and set it to active. Remove the empty ScheduledReminders changelist when you are prompted to do so. Figures 7-30 and 7-31 demonstrate this flow.
你可以在master分支上为拖延者添加一个新功能。这个新功能会把所有的提醒事项设置为默认,因为我们知道拖延者会忽略一切东西,但他不会忽略最重要的提醒事项。点击File ? VCS ? Git ?分支,查看分支列表。选择master分支然后选择检验按钮。注意下面的源文件已经被更改了,并且所有的更改
都支持被清楚的新功能,在你开始设置scheduled reminders之前,你的项目已经被恢复到它的合适状态上了。新建一个名为修改列表的列表并激活它。当你被提示删除被清空的ScheduledReminders修改列表时,删除它。图7-30 和7-31 显示了这个工作流。
Figure 7-30. New changelist dialog box
【翻译】图7-30 新的更改列表对话框
Figure 7-31. A confirmation dialog box appears when deleting the old changelist
【翻译】图7-31 当删除旧的更改列表时出现的确认对话框
Look in the fireCustomDialog() method and find the line that retrieves the check box from the dialog box layout. Add a new line to call checkBox.setChecked(true), which will set the new default, as shown on line 200 in Figure 7-32.
【翻译】查看fireCustomDialog()method,找到对话框设置图中、可以检索复选框的行。添加新的一行来调用checkBox.setChecked(true)文件 这个文件可以设置新的默认,如图7-32中的200行所示。
Figure 7-32. Set the check box default to checked
【翻译】图7-32 把复选框设置为已被检验
Build and run the app to test the new feature and then commit using Ctrl+K | Cmd+K. Git will see the history documented in Figure 7-33, which represents your latest commit that follows your initial clone from the branch.
【翻译】建立并运行这个应用程序来测试新功能,然后用Ctrl+K| Cmd+K提交。Git会查看如图7-33所示的被记录后的历史,这项历史纪录代表了你最新的提交,它紧跟你在分支上的初始克隆之后。
Figure 7-33. Commit history after adding a feature to the master branch
【翻译】图7-33 在主分支上添加新功能后的提交历史
Here you switched your HEAD to master and made a D commit. This latest commit follows a different historic path than the commits for the ScheduledReminders feature, as this commit is not on the same branch.
【翻译】现在把你的HEAD切换到主分支,然后作提交D。较之于ScheduledReminders功能上的提交,这个最新提交有一个不同的历史路径,因为这个新提交是在另外一条分支上。
Note If you are following the history in Git log view, you will note there is another origin/master branch pointing to the A commit that we do not show.This is a remote branch that is discussed later.
【翻译】注意如果你在Git日志视图中追踪历史,你会注意到一个没有被显示的、指向提交A的另一个源/主分支。我们将在后面探讨探讨这个远程分支。
You have done some work on the master branch, and made a few commits to add a new feature on your ScheduledReminders branch, so now you will bring these changes together into the main line, or master branch, where others can see them. Click File ? VCS ? Git ? Branches again to bring up a list of branches. Select the ScheduledReminders branch and click Merge. All of the changes and history from that branch will be incorporated into your master branch. Build and run the app to test both features. Clicking New Reminder from the options menu will open a New Reminder dialog box with the Important check box selected, while clicking any reminder in the list gives the option to schedule the reminder for a certain time. Figure 7-34 illustrates how Git has managed your changes.
【翻译】你已经在你的主分支上完成了一些工作,你也通过作一些提交,为你的ScheduledReminders分支上添加了一个新功能,所以现在你可以把这些更改整合到主线或主分支中以便他人查看。再次点击File? VCS ? Git ?分支,生成一个分支列表。选择ScheduledReminders分支,然后点击合并。这样ScheduledReminders分支上所有的历史和更改都会被合并到你的主分支上。创建并运行这个应用程序开始测试历史和更改两项功能。点击选项菜单中的New Reminder,选择重要复选框,打开New Reminder对话框。点击列表中的任何reminder以让这个选项在某些时刻设置提醒事项。图7-34 显示了Git会如何处理你的更改。
Figure 7-34. Commit history after merging the ScheduledReminders feature
【翻译】图7-34 合并ScheduledReminders功能后的提交历史
A new E commit was automatically performed that includes changes from both C and D (E’s parents). Also note that HEAD is pointing to the head of the master branch which includes the latest commit.
【翻译】一个新的提交E被自动执行,它包含了C以及D的更改(E的父级)你还要注意HEAD是指向指向包含最新提交的主分支上的head。
【翻译】如果你想要把你的重要提醒功能设置为一个分支,你该如何做?你从未替这个功能创建过分支。你不需要在主分支的右上方来进行开发你可以
让你的主分支备份并指向你的提交D,现在就让做这个吧。点击File
? VCS ?Git并且点击 reset Head设置To Commit字段到HEAD中。把这个字段设置到HEAD~1 上,然后点击如图7-35所示的重置按钮再次重置你看起来更像是标签的一个主分支。记得还原那些被保留在Git重置中的更改。然后它会指向之前的提交。Git会查看在图7-33上的图表上大致描绘出的版本库。
Figure 7-35. Git reset dialog box
【翻译】图7-35 Git重置对话框
Since the last commit included the merged changes, the reset makes it such that the merge never happened and you are now sitting on top of the commit, which introduced the ImportantReminders feature. This leaves you free to change history and make it look as if this new feature was developed on a branch. Click File ? VCS ? Git and then click Branches to open the branches dialog box. Click New Branch. Give the branch the name ImportantReminders and click OK to create it. You now have the history depicted in Figure 7-36.
【翻译】因为上一次提交包含了合并后的更改,重置会抹去该次合并痕迹,现在你拥有了所有介绍重要提醒事项功能的提交。这会让你自由地更改历史,并且让更改历史看起来似乎是在分支上开发的新功能。点击File ? VCS ? Git,然后点击分支来打开分支对话框。点击新的分支为这个分支命名为 ImportantReminders,点击确定来新建它。看图7-36,它描绘了整个项目历史。
Figure 7-36. Git history showing the new branch
【翻译】图7-36 显示新分支的Git历史
Both master and ImportantReminders branches are pointing to the same commit. Check out the master branch using the Branches dialog box which can be invoked by clicking the branches section along the right corner of the status bar or by selecting File ? VCS ? Git? Branches. Reset this branch one more time to point it to where you initially cloned the project from Bitbucket and then check out the ImportantReminders branch. The history is now reflecting two experimental feature branches still in development while the working copy (what you see in the IDE) reflects the project as it existed when you first cloned it. You can see this in Figure 7-37.
【翻译】主分支和重要提醒事项分支都指向同样的命令。用分支对话框来检验主分支,你可以通过点击状态栏右角的分支部分或选中 File ? VCS ? Git? Branches来调用该对话框。再一次重置这个分支,把它指向从Bitbucket上最初克隆的那个项目,然后检验重要提醒事项分支。尽管这个工作副本(在IDE中)反映的是当这个项目存在时你第一次克隆它的时间,。这个历史现在反映的是两项正在开发的实验型功能分支。你可以在图7-37中看到这些。
Figure 7-37. Git history after resetting master to the beginning
【翻译】图7-37 重置master到begining后的Git历史
Now you want to further change history and reorder your feature commits so that they look like they were developed in series and no branches were used during development.
Before you do this, check out the master branch and merge it with the ImportantReminders
branch. The merge will result in a special Fast Forward operation: Git merely moves the master branch forward in history to the same commit shared by the ImportantReminders branch. This is different from the earlier merged branch example, because one branch is a descendant of the other. If you look close enough, you will notice that creating a commit that merges changes from the ImportantReminders branch onto the master would be identical
to the D commit already pointed to by this same branch. Consequently, Git optimizes the operation and just moves the master branch forward, which brings you back to the history similar to that illustrated in Figure 7-36. The difference is that you have master checked out instead of the ImportantReminders branch.
Now you’ll make your history more interesting. You will add an About dialog box to your app so your users know a little more about the developer. An About dialog box is also a good place to put attributions for technologies and artwork used. Yours will be relatively simple.
Delete the ImportantReminders changelist if you haven’t done so and work with a new changelist titled AboutScreen. Create a new resource XML file under app ? src ? main ? res ? layout named dialog_about.xml and fill it with the code in Listing 7-1.
【翻译】现在你需要进一步更改记录,重新排序功能提交,既让它们看起来像是被连续开发的,又让它们看起来似乎不使用分支来进行开发。在你做这个之前,检查主分支并把它与重要提醒事项分支关联。
关联会产生一个特殊的Fast Forward操作:Git仅仅是把历史上的主分支移动到与重要提醒事项分支共享的同一个提交上。这与之前的关联分支例子不一样,因为那里的一个分支是另外一个分支的子分支。如果你观察得足够仔细,你会注意到创建一个从ImportantReminders分支到master分支的合并更改命令与指向master分支的提交D是一模一样的。结果就是, Git优化运算,转移分支,把你带回与图7-36所示的相似的历史。不同点就是你需检验master分支而非ImportantReminders分支。
现在你可以让你的历史更加吸引人了。你需要添加一个About对话框到你的应用程序上,这样你的用户就可以对开发人员稍作了解。一个About对话框也是一个放置技术属性与使用过的图形的好位置。yours相对而言会简单一点。
如果你还没有删除ImportantReminders更改列表,现在删除它。然后开始使用名为 AboutScreen的新的更换列表。在app ? src ? main ? res ? layout named dialog_about.xml 下新建resource XML文件,用列表 7-1中的代码填写。
Listing 7-1. dialog_about.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:text="Reminders!"
android:id="@+id/textView2" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" />
<TextView
android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Version 1.0\nAll rights reserved\nDeveloped by yours truly!" android:id="@+id/textView3"
android:layout_marginTop="34dp" android:layout_below="@+id/imageView" android:layout_centerHorizontal="true" android:gravity="center" />
<ImageView
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:id="@+id/imageView" android:layout_below="@+id/textView2" android:layout_centerHorizontal="true" android:src="@drawable/ic_launcher" />
</RelativeLayout>
This layout defines an About dialog box that contains a text view for the title, a text view for the body, and places your Reminders launch icon in between. You need a new menu item to trigger the dialog box. Open menu_reminders.xml and add the following XML snippet between the first and second item tags:
【翻译】这个布局定义了一个包含名为文本视图、正文为文本视图的about对话框,现在把你的Reminders启动图标放在中间。你需要一个新的菜单选项来启动这个对话框。打开menu_reminders.xml ,在第一和第二项标签中添加下面的XML 片段:
<item android:id="@+id/action_about" android:title="About" android:orderInCategory="200" app:showAsAction="never" />
Change the orderInCategory for the Exit menu item from 200 to 300 so it can be ordered after the new About item.
Now open RemindersActivity.java and add a case for the new menu item that calls a new
fireAboutDialog method, as shown in Figure 7-38.
【翻译】在退出菜单选项中把orderInCategory从200更改为300,这样它就能被排在新建的About项之后。
现在打开 RemindersActivity.java ,为新建的称为fireAboutDialog method的菜单选项添加一个事项,如图 7-38所示。
Figure 7-38. Add an About screen
【翻译】图7-38 添加一个About界面
The fireAboutDialog() method builds a dialog box using your new layout and shows it. Build and run the new feature to test it. Finally, press Ctrl+K | Cmd+K and commit with the message Adds an About screen. The Git history now has one more commit after the important reminders feature that is now pointed to by a branch. Your latest E commit from Figure 7-39 includes the About dialog box feature.
【翻译】fireAboutDialog()method可以通过新的布局创建了一个对话框并把它展示出来。创建并运行你的新功能来对它进行测试。最后,按住Ctrl+K | Cmd+K,用Adds an About screen字段进行提交。在重要提醒事项功能通过分支进行指向后,Git历史现在会再有一次提交。图7-39 中的最新的提交E,它包含了About对话框功能。
Figure 7-39. Git history after adding the About screen
【翻译】图7-39 添加About界面的Git历史
Git Rebase
Rebasing is a means of making a branch based on another branch or series of commits. It is similar to a merge in that it combines changes between branches but it does so in a way that creates a commit history without multiple parents. It’s best to use the current history as an example. Click File ? VCS ? Git ? Rebase to open the Rebase Branch dialog box. Tell this dialog box that you want to rebase the master branch on to the ScheduledReminders branch by selecting it from the Onto drop-down menu, as shown in Figure 7-40. Keep the Interactive option selected so you can have more control on what gets combined.
【翻译】Rebase是一种以另一个分支或者另一系列的提交为基础而创建分支的方式。与合并类似,git rebase也把分支之间的更改合并起来。但是,它是以创建一个没有多重父级的提交历史的方式把它们联系起来的。使用当前历史作为示例是最恰当的。点击File ? VCS ? Git ?Rebase,打开Rebase 分支对话框。命令你的对话框rebase 主分支到ScheduledReminders分支上,从Onto下拉菜单上选中它, 如图7-40所示。一直选中交互选项,这样你就可以在被关联的选项中有更多的选择。
Figure 7-40. The Git Rebase branch dialog box
【翻译】图7-40 Git Rebase分支对话框
This takes you into interactive rebase mode presenting the dialog box in Figure 7-41. Interactive rebasing is one of Git’s more powerful features. From here, you can remove and change individual commits in your commit history. The Rebasing Commits dialog box lists all of the commits that occur in the selected branch’s history, up to the first common ancestor of the branch you are basing “onto”. One of the first things to note are options under the Action column for each commit. The dialog box gives the option to pick, edit, skip, or squash. However, Android Studio defaults each commit to pick.
【翻译】它会让你进入如图7-41所示的、演示对话框的交互rebase模式,交互rebase是git最强大的功能之一。在这儿,你可以在你的提交历史中删除并更改个人提交。Rebase提交对话框列出了发生在你选择提交历史上的所有提交,它甚至多到包含了正在base的分支上的第一个common ancestor。你首先应该注意到的就是在每一项提交的Action栏下方的选项。对话框可以让选项进行挑选、编辑、跳过或者粉碎等操作。不过, Android Studio把每一次提交默认为挑选。
Figure 7-41. The Git Rebase commits dialog box
【翻译】图7-41 Git Rebase提交对话框
Let’ say you no longer want the ImportantReminders feature from this branch but you are still interested in your About screen. Chose the Skip action to remove this commit from the list, and none of those changes will be present when you finish your rebase and combine the branches. Click the Start Rebasing option to complete the operation. Your Git history will now look like Figure 7-42.
【翻译】让我猜猜,你现在可能不需要这个分支上的ImportantReminders功能了,但是你仍然对About界面感兴趣。选择Skip操作清除列表上的提交,当你完成对分支的rebase和关联后,这些更改都不会被显示。点击开始Rebase选项,完成操作。你的Git历史会看起来像图7-42中所示的一样。
Figure 7-42. After rebasing and skipping the ImportantReminders branch
【翻译】图7-42 在rebase和跳过重要提醒事项分支之后
We will now demonstrate an alternate way of working in Git, which is known as Detached HEAD mode. If you check out a particular commit rather than a branch, the HEAD is detached from whichever branch you are working under and exposed. First you need
to check out the parent commit to the ImportantReminders branch. To do this, open the Branches dialog box and click Checkout Tag or Revision, as shown in Figure 7-43.
现在我们向你演示在Git上工作的另一种方法,它被称为Detached HEAD模式如果你检验的不是一个分支,而是一项特殊的提交,HEAD会脱离你正在操作的任意一项提交,并且把这个显示出来。首先你需要检查ImportantReminders分支上的父级提交。为了完成这一步,打开分支对话框、点击Checkout标记或Revision, 如图7-43所示。
Figure 7-43. Checking out the change prior to the last change in the ImportantReminders branch
【翻译】图7-43 检验ImportantReminders分支上的上一次更改之前的更改
Enter ImportantReminders~1 in the Checkout prompt. You will now be in detached mode, and your HEAD branch as well as your project state will reflect the last commit made when you initially cloned the project, as shown in Figure 7-44.
【翻译】进入检验提示窗口的ImportantReminders~1 现在你处于detached模式中,你的HEAD分支以及项目状态会反映你最初克隆这个项目时作的最后一次提交,如图7-44所示。
Figure 7-44. git_diagram8
【翻译】图7-44 git图8
Note that Git now exposes a new HEAD, which is detached from any branch that was created as part of your development. The HEAD had formally followed whichever branch you had checked out. As you made commits, the checked-out branch would move along with the HEAD to the latest commit. The ImportantReminders~1 text you entered was a relative reference to where you wanted your checkout to start. You can give a relative reference to most operations that expect a branch or commit hash. Relative references use one of the following two formats:
【翻译】注意Git现在会显示一个新的HEAD,它与任何分支都是分开的,被创建作为你程序开发中的一部分。HEAD会正式地跟踪你之前检验过的任意一个分支。当你作出提交时,检查分支会与head一起转移到最新的提交上。你键入的ImportantReminders~1 text文本是你开始进行检验的区域内的相对参照。对于大部分需要分支或提交哈希代码的操作,你都可以运用相对参照。相对参照选用下面两种格式之一:
BranchOrCommitHash^ BranchOrCommitHash~NumberOfStepsBack
The single-caret form takes a single step back in history from the branch or commit specified to the left, while the tilde form takes a number of steps back in history that is equal to the number given to the right of the tilde.
【翻译】single-caret形式从分支上仅需一步就可以从分支中进入历史或专门向左栏提交,然而tilde形式需花与向右栏进行提交的相同的步骤才能进入历史。
They use a starting point, or point of reference, and a target that is given as the number of steps from the point of reference. While the reference is frequently given as HEAD, it can also be either the name of a branch or the hash code (or abbreviated hash code) of a specific commit. You can use relative references for tasks such as moving a branch anywhere in your Git history, selecting a particular commit, or moving your HEAD to a
specific point in history. A relative reference can be given as a parameter anywhere a branch name or commit hash can be given. While we’ve seen a couple of examples of using them in the IDE, they are best used with Git on the command line.
Create a new branch to begin your next feature and call it SetAlarm. Create a changelist to go with the new branch and delete any old empty changelists. Add a new class in the com.apress.gerber.reminders package called RemindersAlarmReceiver and fill it with the following code:
相对参照使用来自参照点上的几个步骤来进行工作,如一个开始点、参照点或目标点。尽管参照经常被称为HEAD,它也可以作为一个特殊提交上的分支名或哈希代码(或哈希代码缩写)。你可以使用相对参照来完成任务,比如说你可以在git历史上把分支移动到任何地方,选中一个特殊的提交或把你的head移动到历史上的特殊点。
s相对参照可以在任何命名分支名或提交哈希代码的区域内作参数使用。尽管在IDE中使用它们比较常见,在命令行中用Git使用它们其实才是最合适的。
创建一个新的分支来开始你的下一个功能,把它称作 SetAlarm.新建一个更改列表来与新建的分支匹配,删除空的旧列表。在被称作RemindersAlarmReceiver的数据包 com.apress.gerber.reminders 中添加一个新的class,并且在它里面填入下列代码:
public class ReminderAlarmReceiver extends BroadcastReceiver{ public static final String REMINDER_TEXT = "REMINDER TEXT";
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onReceive(Context context, Intent intent) {
String reminderText = intent.getStringExtra(REMINDER_TEXT);
Intent intentAction = new Intent(context, RemindersActivity.class); PendingIntent pi = PendingIntent.getActivity(context, 0, intentAction, 0); Notification notification = new Notification.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setTicker("Reminder!")
.setWhen(new Date().getTime())
.setContentText(reminderText)
.setContentIntent(pi)
.build();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, notification);
}
}
Here we have a BroadcastReceiver that expects REMINDER_TEXT given as an intent extra. It uses the text and creates an action intent, which it uses to build a notification to post in the notification tray. Next add the following entry in AndroidManifest.xml after the activity tag, just before the closing application tag, to define the BroadcastReceiver:
【翻译】现在我们就拥有了一个需要REMINDER_TEXT作为附加内容的BroadcastReceiver REMINDER_TEXT作为附加内容。它使用这个文本并且新建了一个操作内容来创建一个通知表中显示的通知。接下来,在activity标签后,在AndroidManifest.xml中添加下列项目。 在关闭应用标签前,定义BroadcastReceiver为:
<receiver android:name="com.apress.gerber.reminders.ReminderAlarmReceiver"/>
Press Ctrl+K | Cmd+K and commit the SetAlarm changelist with the message Adds BroadcastReceiver for alarms. Your Git history will resemble Figure 7-45 with a third commit hanging off your initial starting point at A.
【翻译】按住Ctrl+K | Cmd+K,用Adds BroadcastReceiver for alarms字段提交SetAlarm更改列表。你的git历史会类似于图7-45 所示,在A初始点会有第三个提交。
Figure 7-45. Git history after committing to the SetAlarm branch
【翻译】图7-45 提交到SetAlarm分支之后的git历史
This feature by itself will not do much of anything on its own. It needs to be merged with the ScheduledReminders feature, which lives on its own branch. To wrap up your work, you need to combine these two features and push them to your remote Bitbucket host, but you want to do this in a way that makes it look like it was done by one person or one team on the main branch and clean up all of your other branches. Earlier you saw how a Git merge creates a commit with two parent commits from both branches involved in the merge. You also learned that a Git rebase combines two branches in a linear way with a single parent commit, which is exactly what you need. Open the Branches dialog box and check out the master branch. Click File ? VCS ? Git ? Rebase. Choose SetAlarm as the branch you are basing onto and deselect the Interactive check box since you now want to include all of your changes from the trunk. Click Start Rebasing. You should get the error pop-up shown in Figure 7-46.
【翻译】提交到SetAlarm分支之后的历史本身并不能实现很多功能。它需要与独立存在于各自分支上的ScheduledReminders功能合并才能发挥作用。为了完成你的工作,你需要合并这两项功能并把它们push到你远程的Bitbucket主页上。但是你需要使得它看起来是由一个人或一个团队在主要分支上完成的,你还需要清除所有其他的分支。之前你看到了一个Git合并是如何利用合并内的两个分支上的两个父级提交来新建一个提交,你也学习了你最需要学习的知识点,如用一个以线性方式使用一个父级提交来合并两个分支的Git rebase。打开分支对话框并检验主分支。点击File ? VCS ? Git ?Rebase.选择SetAlarm作为你base的分支,取消选定交互复选框,因为你现在需要把主干中所有的更改都包含进去。点击Start Rebasing.你会看到一个如图7-46所示的错误弹出框。
Figure 7-46. Rebase conflict pop-up
【翻译】图7-46 Rebase 冲突弹出框
Resolving Conflicts While Rebasing
The pop-up should not alarm you, as it points out that Git has found some conflicts. Git marks files that it cannot automatically merge with a conflict status. It is up to you to resolve these conflicts before the rebase can continue. Traditionally, conflict resolution has been the bane of many collaborative efforts. It is natural to feel uncomfortable when you encounter an error or conflict, especially during a merge. However, familiarizing yourself with the not-so-happy path of collaboration and making merges and conflict resolution a habit,increases your ability to coordinate changes across teams and individuals. Also, Android Studio makes resolving such conflicts much less painful. Remember that you started the BroadcastReceiver in your master branch as part of the ScheduledReminders feature. This conflict comes as a result of code in two branches containing similar or identical changes. Find the conflict in the Changes view by looking for the files highlighted in red, as shown in Figure 7-47.
【翻译】在rebase时解决冲突
弹出框会指出git发现的一些冲突,但它不会向你预警。Git会标记那些不能与冲突状态自动合并的文件。在继续rebase之前,你需要解决这些冲突。传统上,冲突解决办法一直是许多协作工作中的大麻烦。当你遭遇一个错误或冲突时,觉得不愉快是非常自然的。但如果你在合并时中遇到它们,那感觉会更糟糕。
然而,深谙这些不太愉快的合作方式并把合并和解决冲突当成习惯,这会增强你在个体间甚至团队中的应变能力。而且,通过使用Android Studio,你会更容易解决这些冲突。记得你启动过主分支上的BroadcastReceiver作为ScheduledReminders 功能的一部分。这个冲突是缘于两个分支内的代码,它包含类似或相同的更改。寻找标红的文件,找到更改视图中的冲突,如图7-47所示。
Figure 7-47. Merge conflicts in the Changes view
【翻译】图7-47 在更改视图中Merge冲突
Right-click and choose Git ? Resolve Conflicts from the context menu, as shown in
Figure 7-48. This will launch the Files Merged with Conflicts dialog box. Resolving confllicts traditionally consists of two parties offering two sources of input; your local changes or yours, and their incoming changes or theirs.
【翻译】右击并选中内容菜单中的Git ? Resolve Conflicts。
如图7-48所示。这会你可以启动Files Merged with Conflict对话框。解决冲突一般需要双方提供两种输入来源,你当地的更改以及yours,他们即将发布的更改以及theirs。
Figure 7-48. Select the Resolve Conflicts option
【翻译】图7-48 选中解决冲突选项
The Android Studio Files Merged with Conflicts dialog box shown in Figure 7-49 is a powerful merge tool for performing three-way file merges and resolving text conflicts. It borrows yours vs. theirs terminology from the traditional merge scenario as it guides you through the merge. The merge tool considers the SetAlarm branch you are rebasing onto as theirs, or the incoming server changes. The master branch you are rebasing from is considered yours, or the local working copy. The Files Merged with Conflicts dialog box starts with a dialog box that allows you to Accept Yours, Accept Theirs, or Merge. The Accept Yours option totally ignores the incoming server file update from the branch you are rebasing onto in favor of the changes from the local working copy branch you are rebasing from and marks the file as resolved. The Accept Theirs option completely replaces your current branch’s local working copy with the incoming server file updates from the branch you are rebasing onto while marking the file as resolved. The Merge option takes you into the three-way merge editor, where you can pull in individual line changes from the incoming server and working copies into the base merge copy while custom merging only the things you need. The base merge copy is the output, or result, of the merge.
【翻译】如图7-49所示的Android Studio Files Merged with Conflicts对话框是一个强大的合并工具,能够完成三方文件归并,解决文本冲突。它会从传统的合并方案中借用yours vs. theirs术语来指导你进行合并。合并工具会把你正在rebese的SetAlarm分支作为theirs或者incoming server changes,把你正在base的主分支当成yours或当地工作副本。Files Merged with Conflicts对话框以一个对话框的形式开启,它能允许你进行Accept Yours, Accept Theirs或合并等操作。Accept Yours选项完全忽视你正在rebase的分支上的incoming server file updata,而是支持你当地工作副本分支上的更改并把这个文件标记为已解决。Accept Theirs选项用你正在rebase的分支上的incoming server file update来完全取代你当前分支上的当地工作副本,并把该文件标记为已解决。合并选项引导你使用三方归并编辑器,当你专门合并你需要的项目时,你可以在这个编辑器上从incoming server和工作副本中把individual line changes 拉入base 合并副本中,其中base合并副本是合并的输出或结果。
Figure 7-49. Merge the ReminderAlarmReceiver
【翻译】图7-49 合并ReminderAlarmReceiver
Click the Merge button to see how this works. The merge editor shown in Figure 7-50 opens.
【翻译】点击合并按钮,看看它如何运行。合并编辑器如图7-50 所示。
Figure 7-50. The Merge editor
【翻译】图7-50 合并编辑器
The Merge editor lines up your working copy and the incoming copy on either side of the Merge Result, which is the editable part of the screen. It is syntax and import aware, which means you can use auto-complete and quick-fix and other keyboard shortcuts as you
edit the local copy. This gives you certain advantages not present in external VCS merge tools. The editor shows both the local working copy and the incoming update, which is marked Changes from Server. These are the changes from the SetAlarm branch that you are rebasing onto. Along the sidebars, you’ll see little double chevrons and Xs next to the changed lines. Clicking a double chevron from either side will include that particular change in your merge result. Clicking the X will omit that particular change. The changes are also color coded, red for a conflict, green for additional lines, and blue for changed lines. In this case, the majority of the file is conflicting.
Since you have only a stub of the class in your local copy on the left, it makes more sense to accept the entirety of the complete implementation from the right incoming changes. Click Cancel and answer Yes to the prompt asking if you want to exit without applying changes.
Click Accept Theirs in the Files Merged with Conflicts dialog box to take the entire incoming server changes. The dialog box lines up the mainfest file next. If you click Merge, you will see that the local working copy has the exact same modification as the incoming server copy, so you can choose either Yours or Theirs. Click the double chevron from the local working copy to accept your change and the X in the incoming copy pane to deny theirs.
Click Save and Finish from the prompt that pops up to complete your merge. Both files will be marked as conflict resolved for Git. If you look in the Changes tool window, you will see files you merged in the Default changelist. Git has paused in the middle of replaying the series of changes onto the ScheduleAlarm branch and is waiting for you to continue.
Go to the main menu and find the VCS ? Git ? Continue Rebasing option, as shown in Figure 7-51. Note you also have the option of either aborting the rebase or skipping this commit while rebasing. If you were in the middle of a complicated merge and realized something was catastrophically wrong, you could click Abort Rebasing and return everything to the state it was in prior to starting the rebase. If you accidentally included a commit
with several conflicts, you also have the option of skipping. Click Continue Rebasing to finish the rebase.
【翻译】合并编辑器会把你的工作副本以及可在界面中编辑的任意一边的合并结果中的incoming副本排成一行。它是syntax和import aware, 这意味着当你编辑本地副本时,你可以使用自动完成、快速修改以及其他键盘快捷方式来进行相关操作。
编辑本地副本合并编辑器也还有一些其他的VCS合并工具中没有的优势。这个编辑器既显示了当地工作副本,也显示了服务器上被标记为更改的incoming update。这些是你正在rebase的来自SetAlarm分支的更改。沿着边栏,你会看到小标签double chevrons和修订行旁边的Xs。从任意一边点击double chevron,这样会让你的合并结果中显示特殊的更改。点击X可以删除这一特殊更改,这些更改也是被彩色编码的。其中红色表示冲突,绿色代指添加行,蓝色指修改行。在这样情况下,大部分文件都是冲突的。
因为你在左侧的当地副本中仅有一小段class, 所以完全接受右侧的incoming changes中的complete implementation将更有意义。点击取消按钮,在询问你“是否在不应用更改的情况下退出”的提示窗口中回答是。
在Files Merged with Conflicts对话框中点击Accept Theirs,进行完整的incoming server更改。接着对话框会把显示文件排列成行。如果你点击合并按钮, 你会看到当地工作副本与incoming server副本拥有完全一致的更改,所以你既可以选择Yours选项,也可以选择Theirs选项。点击当地工作副本上的double chevron,接受your 更改以及incoming copy窗格中的X更改,取消theirs.
从跳出的即时窗口点击保存和完成按钮,完成此次合并。这两个文件在git上都会被标记为“已解决”。如果你查看更改工具窗,你会看到你在默认更改列表中合并过的文件。这时Git已经在ScheduleAlarm分支上的replaying更改序列中暂停运行并等待你的下一步操作。
去主菜单找到VCS ? Git ? Continue Rebasing选项, 如图 7-51所示。注意你既可以中止rebase, 也可以在rebase时跳过这项提交。如果你身陷一项被灾难性错误包围的复杂合并中,,点击AbortRebasing选项,把一切还原到你进行rebase前的状态。如果你在提交时不小心地包含进了几项
冲突,选择跳过选项。点击ContinueRebasing来结束此次rebase.
Figure 7-51. Click the Continue Rebasing menu option
【翻译】图7-51 点击Continue Rebasing菜单选项
The rebase will complete, and a new commit is performed. The Git history will reflect a copy of all the changes from the master following the SetAlarm commit in the timeline. This is shown in Figure 7-52.
【翻译】rebase就这样结束了,一项新提交被完成了。Git历史会在时间轴中显示一个副本,它列出了SetAlarm在提交后的来自母版的所有更改。如图7-52所示。
Figure 7-52. Git history after rebasing and fixing conflicts
【翻译】图7-52 rebase和修改冲突后的Git历史
The master contains commits B and C, supporting ScheduledReminders; commit E, which added the About screen; and commit F from the SetAlarm branch. You also decided you no longer want the ImportantReminders feature with your earlier rebase.
The task of setting the alarm and implementing the actual BroadcastReceiver was done on a separate branch but it now looks like a tag, or milestone, in your timeline. To complete your feature, you need to tie your work from the ScheduleReminders branch to the actual BroadcastReceiver in the SetAlarm branch. Make the following change to connect the listener that invokes the BroadcastReceiver to the TimePickerDialog. You will insert the following code snippet at the end of the else block just before the dialog that we use for Edit Reminder.
【翻译】母版包含了支持ScheduledReminders的提交B和提交C、被添加在About界面上的提交E和SetAlarm分支上的提交F.你也决定你不需要用你之前的rebase方式来设置重要提醒功能。
分别在不同的分支上设置aralm和完成实际的BroadcastReceiver等任务结束了, 但现在它在你的时间轴里看起来就像是一个标签或一个里程碑。为了完善你的功能,你需要把你ScheduleReminders分支上的工作转换到到SetAlarm分支上的 BroadcastReceiver中。作出下列更改,把调用BroadcastReceiver 的Listener关联到TimePickerDialog上。在我们使用编辑提醒器对话之前,把下列代码片段插入到每一个block的结尾部分。
new TimePickerDialog(RemindersActivity.this,listener,today.getHours(),today. getMinutes(),false).show();
Run your project on a device and verify that the feature works. You should now get device notifications when you schedule reminders, as shown in Figure 7-53.
【翻译】在一个设备上运行你的项目并确保这个功能能正常运行。当你设置提醒事项时,你会看到一个设备通知, 如图7-53所示。
Figure 7-53. Notification from a reminder
【翻译】图7-53 来自提醒事项上的通知
You can now push your master branch to the remote Bitbucket host. From the File menu, choose VCS ? Git ? Push. The dialog box in Figure 7-54 opens, giving you the ability to push changes from your local master branch to the remote master branch of your Bitbucket repository. Click the Push button to perform the push.
【翻译】你也可以把你的主分支推送到远程的Bitbucket主机上.从这个文件菜单中, 选择VCS ? Git ?Push.接着图 7-54所示的对话框会打开,它能让你从当地的主分支上推送更改到你Bitbucket版本库上的远程主分支。点击推送标签执行此次推送。
Figure 7-54. Push your changes to Bitbucket
【翻译】图7-54 把你的更改推送到Bitbucket上
Since you are done with the ScheduledReminders and ImportantReminders branches, they can be deleted. Open the Branches dialog box and select both of these branches in turn; click Delete to remove them.
【翻译】删除你已经完成了的ScheduledReminders和ImportantReminders分支。打开分支对话框,轮流选中上面两项分支,点击删除。
The pull request is a request from one developer to pull in changes from a public repository under that developer’s profile. Others are free to include individual commits or your entire work at their discretion. You will usually find a main branch, with one or more lead developers responsible for keeping that branch up-to-date with the latest and most valuable features and commits. The leads pull in changes from various contributors by using the entire feature set of Git, which allows the selection, removal, reordering, merging, squashing, and amending of individual commits.
However, pull requests are for advanced Git users. The most common way people begin with Git is by cloning a project from a Git hosting server—downloading an entire copy of the Git repository to work with locally. You continue to make changes and commit them locally, and then finally push these changes back to the remote repository. You can also fetch and merge changes that were pushed by others up to the remote.
Another option is to start with an empty repository locally and build a project. You then push the project to a Git hosting service such as Bitbucket or GitHub and advertise it to be shared with others, or you can make it private and invite others at your discretion. Development continues as in the common approach, with local commits that you push to the remote.
Eventually, contributors fork and add to their remote copies of the project over time as you work, and you will fetch and merge these changes.
pull申请是一项来自一个开发人员的请求,它请求在那个开发人员头像下的的公共版本库内pull更改,其他人可以在他们的审核下,自由地把个人提交或你的
整项工作列入进来。你通常会发现一个主要分支,它由一个或多个核心开发人员负责用最新的、最有价值的功能和提交来更新。这会导致不同贡献者依靠使用整套的Git的功能设置来把更改拖进Git中, 因为它允许选中、删除、重新排序、合并、粉碎和修补个人提交。
然而, pull请求仅针对Git的高级用户。人们打开git的最常见方式是:先从Git主服务器上克隆一个项目来打开git,然后再下载git版本库上的整个副本来在当地工作。你可以继续作出更改并在当地把它们提交出去,然后让这些更改最终被push回远程版本库中。你也可以提取和合并被其他用户push进远程版本库内的更改。
你的另一个选择是是在一个空的版本库上新建一个项目。然后你可以把这个项目push进git主服务器Bitbucket或GitHub中,并把它广而告之以便他人贡献共享。或者你也可以把它设置成个人私有模式,邀请他人在你的审查下进入。随着你把当地提交push到远程版本库,开发会以常用的方式持续进行下去。
最终,贡献者可以在你工作时为你的项目作分支和添加工作,以便你最终可以提取和合并这些更改。
Git follows a distributed pull model treating a project as a shared entity. Because Git allows distributed copies of the master branch, any individual is allowed to commit and update a local copy at any time, which reduces the complexity involved with merging work between contributors. Git also elevates the significance of individual commits, treating them as snapshots of your repository over time. This leaves the tool better adept at managing changes. It also adds the flexibility of managing multiple changes to an individual source file separately. Merges are much more precise and manageable, and the complexity of
combining work is dramatically reduced. For example, a project lead could pull a feature that you’ve implemented in 10 or so commits spread between multiple branches, squash them all into one, amend the message, and organize it in that lead’s personal history before other commits in the master branch, and finally push and publicize it on the remote associated with the project.
Git把一个项目作为共同体,遵循分布式的pull模式。因为Git承认主分支上的分布式副本,所以任何人在任何时候都被允许提交和更新当地副本,这一模式降低为贡献者们降低了合并工作的复杂性。Git也会增强个人提交的重要性,并把这些个人提交视为你当地版本库的快照。这会让它更善于管理更改。而且,它还为管理个人源文件上的多重更改增加了灵活性。并合并更加精确且可控,
极大减少了合并工作的复杂程度。比如说,一个项目负责人可能会pull你完成的散布在多个分支上的十多个提交,一次性全部粉碎这些提交并修改信息并在主分支上的其他提交之前在这个负责人的个人历史中规划这项信息。最终,在与这个项目有关的远程版本库中push并公开它。
and used the Git log feature to see a summary of your commit history. You’ve seen in-depth examples of how branches work like labels pointing to individual commits. The branches can be moved between commits by using relative references or even deleted entirely. We’ve demonstrated how Git history can modify changes that were committed in parallel and line them up serially. We demonstrated a few collaborative scenarios involving multiple branches maturing simultaneously.
并使用Git的日志功能去一览你的提交历史。你也见到了许多关于分支如何像指向个人提交的标签那样运行的详实例子。这些分支可以通过使用相对参照和彻底删除之间的提交来进行移动。我们向你展示了git历史是如何修改以平行或序列线形方式提交的更改。最后,我们还向你展示了一些包含多重分支共同成熟完善的合作场景。
【翻译】让我们进一步重置,使用deprecated method calls清除你项目工作中的所有追踪。选择VCS ? Git ?Reset Head.进入弹出对话框中的HEAD~2 ,如图7-28所示,然后点击重置。接着,记得点击重置更改按钮,把这个养成习惯,日后每当你在Android Studio中使用Git重置时,记得点击它。你的历史会在图7-22中反映出来。
REVERT VS. RESET
【翻译】还原VS.重置
The difference between revert and reset is subtle but important. A revert adds a commit that inverts the changes from the last commit, whereas reset takes a commit away. A reset essentially backs your branch label up by a given number of commits. If you’ve accidentally committed something, you’ll often want to undo or delete a commit. It is reasonable to use reset in such cases, because it is the simplest option and does not add to your history. In some cases, however, you might want your history to reflect the work of unwinding a commit—for example, if you pull a feature from a project and want to document the removal of that feature to the user community. Another important use for revert comes with remote repositories, which we discuss later in this chapter. Because you can only add commits to remote repositories, the only way to remove or unwind a commit on a remote repository is to use a revert, which appends the inverted changes as a commit.【翻译】还原和重置之间的差别虽然很小,但很重要。尽管重置会撤销上次提交中的更改,还原却可以把它再添加回来。通过许多提交,还原可以备份你的分支标签。如果你无意中作了一项提交,你经常需要撤销或删除它。在这样的情况下使用重置是相当恰当的,因为它是最简单的选项,而且不会被添加到项目历史里。然而在一些情况下,你可能想要你的项目历史反映解除提交的工作。比如说,如果你从一个项目中pull一个功能并且想把这次功能清楚记录到用户社区上。还原的另一个功能是应用在远程版本库上,将在本章的后部分讨论。因为你仅仅可以添加提交到远程版本库,所以在远程版本库上删除或展开一项命令的唯一方式是使用还原功能,它能把inverted 更改添加为提交。
Merging
Merging is a means of combining work from two separate branches. Historically, merges have required extra effort because of conflicts between branches. Thanks to Git’s implementation of changes, merges have become less painful.You’ll start by adding a new feature on the main branch for the extreme procrastinator. This new feature will set the default of all reminders to Important because we know you procrastinators will ignore anything other than the most important reminders. Click File ? VCS ? Git ? Branches to bring up a list of branches. Select the master branch and then select Checkout. Note that the underlying source has been changed, all of the changes to
support the new feature have been removed, and your project has been restored to its state before you began working on scheduled reminders. Create a new changelist entitled and set it to active. Remove the empty ScheduledReminders changelist when you are prompted to do so. Figures 7-30 and 7-31 demonstrate this flow.
【翻译】合并
【翻译】合并是一种把两个不同分支上的工作联系起来的方式。在以前,因为不同分支之间的冲突,合并需要承担多余的工作,不便于使用。因为有Git更改的存在,合并现在容易多了。你可以在master分支上为拖延者添加一个新功能。这个新功能会把所有的提醒事项设置为默认,因为我们知道拖延者会忽略一切东西,但他不会忽略最重要的提醒事项。点击File ? VCS ? Git ?分支,查看分支列表。选择master分支然后选择检验按钮。注意下面的源文件已经被更改了,并且所有的更改
都支持被清楚的新功能,在你开始设置scheduled reminders之前,你的项目已经被恢复到它的合适状态上了。新建一个名为修改列表的列表并激活它。当你被提示删除被清空的ScheduledReminders修改列表时,删除它。图7-30 和7-31 显示了这个工作流。
Figure 7-30. New changelist dialog box
【翻译】图7-30 新的更改列表对话框
Figure 7-31. A confirmation dialog box appears when deleting the old changelist
【翻译】图7-31 当删除旧的更改列表时出现的确认对话框
Look in the fireCustomDialog() method and find the line that retrieves the check box from the dialog box layout. Add a new line to call checkBox.setChecked(true), which will set the new default, as shown on line 200 in Figure 7-32.
【翻译】查看fireCustomDialog()method,找到对话框设置图中、可以检索复选框的行。添加新的一行来调用checkBox.setChecked(true)文件 这个文件可以设置新的默认,如图7-32中的200行所示。
Figure 7-32. Set the check box default to checked
【翻译】图7-32 把复选框设置为已被检验
Build and run the app to test the new feature and then commit using Ctrl+K | Cmd+K. Git will see the history documented in Figure 7-33, which represents your latest commit that follows your initial clone from the branch.
【翻译】建立并运行这个应用程序来测试新功能,然后用Ctrl+K| Cmd+K提交。Git会查看如图7-33所示的被记录后的历史,这项历史纪录代表了你最新的提交,它紧跟你在分支上的初始克隆之后。
Figure 7-33. Commit history after adding a feature to the master branch
【翻译】图7-33 在主分支上添加新功能后的提交历史
Here you switched your HEAD to master and made a D commit. This latest commit follows a different historic path than the commits for the ScheduledReminders feature, as this commit is not on the same branch.
【翻译】现在把你的HEAD切换到主分支,然后作提交D。较之于ScheduledReminders功能上的提交,这个最新提交有一个不同的历史路径,因为这个新提交是在另外一条分支上。
Note If you are following the history in Git log view, you will note there is another origin/master branch pointing to the A commit that we do not show.This is a remote branch that is discussed later.
【翻译】注意如果你在Git日志视图中追踪历史,你会注意到一个没有被显示的、指向提交A的另一个源/主分支。我们将在后面探讨探讨这个远程分支。
You have done some work on the master branch, and made a few commits to add a new feature on your ScheduledReminders branch, so now you will bring these changes together into the main line, or master branch, where others can see them. Click File ? VCS ? Git ? Branches again to bring up a list of branches. Select the ScheduledReminders branch and click Merge. All of the changes and history from that branch will be incorporated into your master branch. Build and run the app to test both features. Clicking New Reminder from the options menu will open a New Reminder dialog box with the Important check box selected, while clicking any reminder in the list gives the option to schedule the reminder for a certain time. Figure 7-34 illustrates how Git has managed your changes.
【翻译】你已经在你的主分支上完成了一些工作,你也通过作一些提交,为你的ScheduledReminders分支上添加了一个新功能,所以现在你可以把这些更改整合到主线或主分支中以便他人查看。再次点击File? VCS ? Git ?分支,生成一个分支列表。选择ScheduledReminders分支,然后点击合并。这样ScheduledReminders分支上所有的历史和更改都会被合并到你的主分支上。创建并运行这个应用程序开始测试历史和更改两项功能。点击选项菜单中的New Reminder,选择重要复选框,打开New Reminder对话框。点击列表中的任何reminder以让这个选项在某些时刻设置提醒事项。图7-34 显示了Git会如何处理你的更改。
Figure 7-34. Commit history after merging the ScheduledReminders feature
【翻译】图7-34 合并ScheduledReminders功能后的提交历史
A new E commit was automatically performed that includes changes from both C and D (E’s parents). Also note that HEAD is pointing to the head of the master branch which includes the latest commit.
【翻译】一个新的提交E被自动执行,它包含了C以及D的更改(E的父级)你还要注意HEAD是指向指向包含最新提交的主分支上的head。
Git Reset Changes History
【翻译】Git重置更改历史
What if you wanted to treat your important reminders feature as a branch? You never created a branch for this feature. Instead you developed right on top of the master branch. You could force your master branch to back up and point to your D commit so let’s do this now. Click File? VCS ? Git and click Reset Head. The To Commit field will be set to HEAD. Set it to HEAD~1 and click the Reset button as shown in Figure 7-35 to reset your master branch again, which is more like a label. Remember to revert the changes saved from the Git reset. It will then point to the prior commit. Git will now see the repository as outlined in the prior diagram in Figure 7-33.【翻译】如果你想要把你的重要提醒功能设置为一个分支,你该如何做?你从未替这个功能创建过分支。你不需要在主分支的右上方来进行开发你可以
让你的主分支备份并指向你的提交D,现在就让做这个吧。点击File
? VCS ?Git并且点击 reset Head设置To Commit字段到HEAD中。把这个字段设置到HEAD~1 上,然后点击如图7-35所示的重置按钮再次重置你看起来更像是标签的一个主分支。记得还原那些被保留在Git重置中的更改。然后它会指向之前的提交。Git会查看在图7-33上的图表上大致描绘出的版本库。
Figure 7-35. Git reset dialog box
【翻译】图7-35 Git重置对话框
Since the last commit included the merged changes, the reset makes it such that the merge never happened and you are now sitting on top of the commit, which introduced the ImportantReminders feature. This leaves you free to change history and make it look as if this new feature was developed on a branch. Click File ? VCS ? Git and then click Branches to open the branches dialog box. Click New Branch. Give the branch the name ImportantReminders and click OK to create it. You now have the history depicted in Figure 7-36.
【翻译】因为上一次提交包含了合并后的更改,重置会抹去该次合并痕迹,现在你拥有了所有介绍重要提醒事项功能的提交。这会让你自由地更改历史,并且让更改历史看起来似乎是在分支上开发的新功能。点击File ? VCS ? Git,然后点击分支来打开分支对话框。点击新的分支为这个分支命名为 ImportantReminders,点击确定来新建它。看图7-36,它描绘了整个项目历史。
Figure 7-36. Git history showing the new branch
【翻译】图7-36 显示新分支的Git历史
Both master and ImportantReminders branches are pointing to the same commit. Check out the master branch using the Branches dialog box which can be invoked by clicking the branches section along the right corner of the status bar or by selecting File ? VCS ? Git? Branches. Reset this branch one more time to point it to where you initially cloned the project from Bitbucket and then check out the ImportantReminders branch. The history is now reflecting two experimental feature branches still in development while the working copy (what you see in the IDE) reflects the project as it existed when you first cloned it. You can see this in Figure 7-37.
【翻译】主分支和重要提醒事项分支都指向同样的命令。用分支对话框来检验主分支,你可以通过点击状态栏右角的分支部分或选中 File ? VCS ? Git? Branches来调用该对话框。再一次重置这个分支,把它指向从Bitbucket上最初克隆的那个项目,然后检验重要提醒事项分支。尽管这个工作副本(在IDE中)反映的是当这个项目存在时你第一次克隆它的时间,。这个历史现在反映的是两项正在开发的实验型功能分支。你可以在图7-37中看到这些。
Figure 7-37. Git history after resetting master to the beginning
【翻译】图7-37 重置master到begining后的Git历史
Now you want to further change history and reorder your feature commits so that they look like they were developed in series and no branches were used during development.
Before you do this, check out the master branch and merge it with the ImportantReminders
branch. The merge will result in a special Fast Forward operation: Git merely moves the master branch forward in history to the same commit shared by the ImportantReminders branch. This is different from the earlier merged branch example, because one branch is a descendant of the other. If you look close enough, you will notice that creating a commit that merges changes from the ImportantReminders branch onto the master would be identical
to the D commit already pointed to by this same branch. Consequently, Git optimizes the operation and just moves the master branch forward, which brings you back to the history similar to that illustrated in Figure 7-36. The difference is that you have master checked out instead of the ImportantReminders branch.
Now you’ll make your history more interesting. You will add an About dialog box to your app so your users know a little more about the developer. An About dialog box is also a good place to put attributions for technologies and artwork used. Yours will be relatively simple.
Delete the ImportantReminders changelist if you haven’t done so and work with a new changelist titled AboutScreen. Create a new resource XML file under app ? src ? main ? res ? layout named dialog_about.xml and fill it with the code in Listing 7-1.
【翻译】现在你需要进一步更改记录,重新排序功能提交,既让它们看起来像是被连续开发的,又让它们看起来似乎不使用分支来进行开发。在你做这个之前,检查主分支并把它与重要提醒事项分支关联。
关联会产生一个特殊的Fast Forward操作:Git仅仅是把历史上的主分支移动到与重要提醒事项分支共享的同一个提交上。这与之前的关联分支例子不一样,因为那里的一个分支是另外一个分支的子分支。如果你观察得足够仔细,你会注意到创建一个从ImportantReminders分支到master分支的合并更改命令与指向master分支的提交D是一模一样的。结果就是, Git优化运算,转移分支,把你带回与图7-36所示的相似的历史。不同点就是你需检验master分支而非ImportantReminders分支。
现在你可以让你的历史更加吸引人了。你需要添加一个About对话框到你的应用程序上,这样你的用户就可以对开发人员稍作了解。一个About对话框也是一个放置技术属性与使用过的图形的好位置。yours相对而言会简单一点。
如果你还没有删除ImportantReminders更改列表,现在删除它。然后开始使用名为 AboutScreen的新的更换列表。在app ? src ? main ? res ? layout named dialog_about.xml 下新建resource XML文件,用列表 7-1中的代码填写。
Listing 7-1. dialog_about.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceLarge" android:text="Reminders!"
android:id="@+id/textView2" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" />
<TextView
android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Version 1.0\nAll rights reserved\nDeveloped by yours truly!" android:id="@+id/textView3"
android:layout_marginTop="34dp" android:layout_below="@+id/imageView" android:layout_centerHorizontal="true" android:gravity="center" />
<ImageView
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:id="@+id/imageView" android:layout_below="@+id/textView2" android:layout_centerHorizontal="true" android:src="@drawable/ic_launcher" />
</RelativeLayout>
This layout defines an About dialog box that contains a text view for the title, a text view for the body, and places your Reminders launch icon in between. You need a new menu item to trigger the dialog box. Open menu_reminders.xml and add the following XML snippet between the first and second item tags:
【翻译】这个布局定义了一个包含名为文本视图、正文为文本视图的about对话框,现在把你的Reminders启动图标放在中间。你需要一个新的菜单选项来启动这个对话框。打开menu_reminders.xml ,在第一和第二项标签中添加下面的XML 片段:
<item android:id="@+id/action_about" android:title="About" android:orderInCategory="200" app:showAsAction="never" />
Change the orderInCategory for the Exit menu item from 200 to 300 so it can be ordered after the new About item.
Now open RemindersActivity.java and add a case for the new menu item that calls a new
fireAboutDialog method, as shown in Figure 7-38.
【翻译】在退出菜单选项中把orderInCategory从200更改为300,这样它就能被排在新建的About项之后。
现在打开 RemindersActivity.java ,为新建的称为fireAboutDialog method的菜单选项添加一个事项,如图 7-38所示。
Figure 7-38. Add an About screen
【翻译】图7-38 添加一个About界面
The fireAboutDialog() method builds a dialog box using your new layout and shows it. Build and run the new feature to test it. Finally, press Ctrl+K | Cmd+K and commit with the message Adds an About screen. The Git history now has one more commit after the important reminders feature that is now pointed to by a branch. Your latest E commit from Figure 7-39 includes the About dialog box feature.
【翻译】fireAboutDialog()method可以通过新的布局创建了一个对话框并把它展示出来。创建并运行你的新功能来对它进行测试。最后,按住Ctrl+K | Cmd+K,用Adds an About screen字段进行提交。在重要提醒事项功能通过分支进行指向后,Git历史现在会再有一次提交。图7-39 中的最新的提交E,它包含了About对话框功能。
Figure 7-39. Git history after adding the About screen
【翻译】图7-39 添加About界面的Git历史
Git Rebase
Rebasing is a means of making a branch based on another branch or series of commits. It is similar to a merge in that it combines changes between branches but it does so in a way that creates a commit history without multiple parents. It’s best to use the current history as an example. Click File ? VCS ? Git ? Rebase to open the Rebase Branch dialog box. Tell this dialog box that you want to rebase the master branch on to the ScheduledReminders branch by selecting it from the Onto drop-down menu, as shown in Figure 7-40. Keep the Interactive option selected so you can have more control on what gets combined.
【翻译】Rebase是一种以另一个分支或者另一系列的提交为基础而创建分支的方式。与合并类似,git rebase也把分支之间的更改合并起来。但是,它是以创建一个没有多重父级的提交历史的方式把它们联系起来的。使用当前历史作为示例是最恰当的。点击File ? VCS ? Git ?Rebase,打开Rebase 分支对话框。命令你的对话框rebase 主分支到ScheduledReminders分支上,从Onto下拉菜单上选中它, 如图7-40所示。一直选中交互选项,这样你就可以在被关联的选项中有更多的选择。
Figure 7-40. The Git Rebase branch dialog box
【翻译】图7-40 Git Rebase分支对话框
This takes you into interactive rebase mode presenting the dialog box in Figure 7-41. Interactive rebasing is one of Git’s more powerful features. From here, you can remove and change individual commits in your commit history. The Rebasing Commits dialog box lists all of the commits that occur in the selected branch’s history, up to the first common ancestor of the branch you are basing “onto”. One of the first things to note are options under the Action column for each commit. The dialog box gives the option to pick, edit, skip, or squash. However, Android Studio defaults each commit to pick.
【翻译】它会让你进入如图7-41所示的、演示对话框的交互rebase模式,交互rebase是git最强大的功能之一。在这儿,你可以在你的提交历史中删除并更改个人提交。Rebase提交对话框列出了发生在你选择提交历史上的所有提交,它甚至多到包含了正在base的分支上的第一个common ancestor。你首先应该注意到的就是在每一项提交的Action栏下方的选项。对话框可以让选项进行挑选、编辑、跳过或者粉碎等操作。不过, Android Studio把每一次提交默认为挑选。
Figure 7-41. The Git Rebase commits dialog box
【翻译】图7-41 Git Rebase提交对话框
Let’ say you no longer want the ImportantReminders feature from this branch but you are still interested in your About screen. Chose the Skip action to remove this commit from the list, and none of those changes will be present when you finish your rebase and combine the branches. Click the Start Rebasing option to complete the operation. Your Git history will now look like Figure 7-42.
【翻译】让我猜猜,你现在可能不需要这个分支上的ImportantReminders功能了,但是你仍然对About界面感兴趣。选择Skip操作清除列表上的提交,当你完成对分支的rebase和关联后,这些更改都不会被显示。点击开始Rebase选项,完成操作。你的Git历史会看起来像图7-42中所示的一样。
Figure 7-42. After rebasing and skipping the ImportantReminders branch
【翻译】图7-42 在rebase和跳过重要提醒事项分支之后
Detached Head
Let’s pretend that you had another developer working on an Alarm feature when you initially cloned the project. Let’s further say that you want to eventually merge in this work. To simulate this, you need to move back in history to the A commit and start the new feature. Until this point, you have been working and committing against a specific branch. This has been either a custom-named branch or the master branch that was created upon the initial import.We will now demonstrate an alternate way of working in Git, which is known as Detached HEAD mode. If you check out a particular commit rather than a branch, the HEAD is detached from whichever branch you are working under and exposed. First you need
to check out the parent commit to the ImportantReminders branch. To do this, open the Branches dialog box and click Checkout Tag or Revision, as shown in Figure 7-43.
【翻译】Detacheded Head
【翻译】让我们假设当你最初克隆这个项目时候,你是和另一位开发人员共通过开发alarm功能的。进一步说,你最终需要对这项任务进行合并merge合并。为了模拟这一步,你需要返回到项目历史中的提交A,并开始这项新功能。直到现在为止,你一直都在一个专门的分支上工作或提交。它要么是常规命名的分支,要么是在最初的import中被创建的主分支。现在我们向你演示在Git上工作的另一种方法,它被称为Detached HEAD模式如果你检验的不是一个分支,而是一项特殊的提交,HEAD会脱离你正在操作的任意一项提交,并且把这个显示出来。首先你需要检查ImportantReminders分支上的父级提交。为了完成这一步,打开分支对话框、点击Checkout标记或Revision, 如图7-43所示。
Figure 7-43. Checking out the change prior to the last change in the ImportantReminders branch
【翻译】图7-43 检验ImportantReminders分支上的上一次更改之前的更改
Enter ImportantReminders~1 in the Checkout prompt. You will now be in detached mode, and your HEAD branch as well as your project state will reflect the last commit made when you initially cloned the project, as shown in Figure 7-44.
【翻译】进入检验提示窗口的ImportantReminders~1 现在你处于detached模式中,你的HEAD分支以及项目状态会反映你最初克隆这个项目时作的最后一次提交,如图7-44所示。
Figure 7-44. git_diagram8
【翻译】图7-44 git图8
Note that Git now exposes a new HEAD, which is detached from any branch that was created as part of your development. The HEAD had formally followed whichever branch you had checked out. As you made commits, the checked-out branch would move along with the HEAD to the latest commit. The ImportantReminders~1 text you entered was a relative reference to where you wanted your checkout to start. You can give a relative reference to most operations that expect a branch or commit hash. Relative references use one of the following two formats:
【翻译】注意Git现在会显示一个新的HEAD,它与任何分支都是分开的,被创建作为你程序开发中的一部分。HEAD会正式地跟踪你之前检验过的任意一个分支。当你作出提交时,检查分支会与head一起转移到最新的提交上。你键入的ImportantReminders~1 text文本是你开始进行检验的区域内的相对参照。对于大部分需要分支或提交哈希代码的操作,你都可以运用相对参照。相对参照选用下面两种格式之一:
BranchOrCommitHash^ BranchOrCommitHash~NumberOfStepsBack
The single-caret form takes a single step back in history from the branch or commit specified to the left, while the tilde form takes a number of steps back in history that is equal to the number given to the right of the tilde.
【翻译】single-caret形式从分支上仅需一步就可以从分支中进入历史或专门向左栏提交,然而tilde形式需花与向右栏进行提交的相同的步骤才能进入历史。
Relative References
Relative references are Git expressions that are used to refer to a specific point in Git history.They use a starting point, or point of reference, and a target that is given as the number of steps from the point of reference. While the reference is frequently given as HEAD, it can also be either the name of a branch or the hash code (or abbreviated hash code) of a specific commit. You can use relative references for tasks such as moving a branch anywhere in your Git history, selecting a particular commit, or moving your HEAD to a
specific point in history. A relative reference can be given as a parameter anywhere a branch name or commit hash can be given. While we’ve seen a couple of examples of using them in the IDE, they are best used with Git on the command line.
Create a new branch to begin your next feature and call it SetAlarm. Create a changelist to go with the new branch and delete any old empty changelists. Add a new class in the com.apress.gerber.reminders package called RemindersAlarmReceiver and fill it with the following code:
【翻译】相对参照
【翻译】相对参照是一种Git表达方式,被用于指代git历史中的专门时刻。相对参照使用来自参照点上的几个步骤来进行工作,如一个开始点、参照点或目标点。尽管参照经常被称为HEAD,它也可以作为一个特殊提交上的分支名或哈希代码(或哈希代码缩写)。你可以使用相对参照来完成任务,比如说你可以在git历史上把分支移动到任何地方,选中一个特殊的提交或把你的head移动到历史上的特殊点。
s相对参照可以在任何命名分支名或提交哈希代码的区域内作参数使用。尽管在IDE中使用它们比较常见,在命令行中用Git使用它们其实才是最合适的。
创建一个新的分支来开始你的下一个功能,把它称作 SetAlarm.新建一个更改列表来与新建的分支匹配,删除空的旧列表。在被称作RemindersAlarmReceiver的数据包 com.apress.gerber.reminders 中添加一个新的class,并且在它里面填入下列代码:
public class ReminderAlarmReceiver extends BroadcastReceiver{ public static final String REMINDER_TEXT = "REMINDER TEXT";
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onReceive(Context context, Intent intent) {
String reminderText = intent.getStringExtra(REMINDER_TEXT);
Intent intentAction = new Intent(context, RemindersActivity.class); PendingIntent pi = PendingIntent.getActivity(context, 0, intentAction, 0); Notification notification = new Notification.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setTicker("Reminder!")
.setWhen(new Date().getTime())
.setContentText(reminderText)
.setContentIntent(pi)
.build();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, notification);
}
}
Here we have a BroadcastReceiver that expects REMINDER_TEXT given as an intent extra. It uses the text and creates an action intent, which it uses to build a notification to post in the notification tray. Next add the following entry in AndroidManifest.xml after the activity tag, just before the closing application tag, to define the BroadcastReceiver:
【翻译】现在我们就拥有了一个需要REMINDER_TEXT作为附加内容的BroadcastReceiver REMINDER_TEXT作为附加内容。它使用这个文本并且新建了一个操作内容来创建一个通知表中显示的通知。接下来,在activity标签后,在AndroidManifest.xml中添加下列项目。 在关闭应用标签前,定义BroadcastReceiver为:
<receiver android:name="com.apress.gerber.reminders.ReminderAlarmReceiver"/>
Press Ctrl+K | Cmd+K and commit the SetAlarm changelist with the message Adds BroadcastReceiver for alarms. Your Git history will resemble Figure 7-45 with a third commit hanging off your initial starting point at A.
【翻译】按住Ctrl+K | Cmd+K,用Adds BroadcastReceiver for alarms字段提交SetAlarm更改列表。你的git历史会类似于图7-45 所示,在A初始点会有第三个提交。
Figure 7-45. Git history after committing to the SetAlarm branch
【翻译】图7-45 提交到SetAlarm分支之后的git历史
This feature by itself will not do much of anything on its own. It needs to be merged with the ScheduledReminders feature, which lives on its own branch. To wrap up your work, you need to combine these two features and push them to your remote Bitbucket host, but you want to do this in a way that makes it look like it was done by one person or one team on the main branch and clean up all of your other branches. Earlier you saw how a Git merge creates a commit with two parent commits from both branches involved in the merge. You also learned that a Git rebase combines two branches in a linear way with a single parent commit, which is exactly what you need. Open the Branches dialog box and check out the master branch. Click File ? VCS ? Git ? Rebase. Choose SetAlarm as the branch you are basing onto and deselect the Interactive check box since you now want to include all of your changes from the trunk. Click Start Rebasing. You should get the error pop-up shown in Figure 7-46.
【翻译】提交到SetAlarm分支之后的历史本身并不能实现很多功能。它需要与独立存在于各自分支上的ScheduledReminders功能合并才能发挥作用。为了完成你的工作,你需要合并这两项功能并把它们push到你远程的Bitbucket主页上。但是你需要使得它看起来是由一个人或一个团队在主要分支上完成的,你还需要清除所有其他的分支。之前你看到了一个Git合并是如何利用合并内的两个分支上的两个父级提交来新建一个提交,你也学习了你最需要学习的知识点,如用一个以线性方式使用一个父级提交来合并两个分支的Git rebase。打开分支对话框并检验主分支。点击File ? VCS ? Git ?Rebase.选择SetAlarm作为你base的分支,取消选定交互复选框,因为你现在需要把主干中所有的更改都包含进去。点击Start Rebasing.你会看到一个如图7-46所示的错误弹出框。
Figure 7-46. Rebase conflict pop-up
【翻译】图7-46 Rebase 冲突弹出框
Resolving Conflicts While Rebasing
The pop-up should not alarm you, as it points out that Git has found some conflicts. Git marks files that it cannot automatically merge with a conflict status. It is up to you to resolve these conflicts before the rebase can continue. Traditionally, conflict resolution has been the bane of many collaborative efforts. It is natural to feel uncomfortable when you encounter an error or conflict, especially during a merge. However, familiarizing yourself with the not-so-happy path of collaboration and making merges and conflict resolution a habit,increases your ability to coordinate changes across teams and individuals. Also, Android Studio makes resolving such conflicts much less painful. Remember that you started the BroadcastReceiver in your master branch as part of the ScheduledReminders feature. This conflict comes as a result of code in two branches containing similar or identical changes. Find the conflict in the Changes view by looking for the files highlighted in red, as shown in Figure 7-47.
【翻译】在rebase时解决冲突
弹出框会指出git发现的一些冲突,但它不会向你预警。Git会标记那些不能与冲突状态自动合并的文件。在继续rebase之前,你需要解决这些冲突。传统上,冲突解决办法一直是许多协作工作中的大麻烦。当你遭遇一个错误或冲突时,觉得不愉快是非常自然的。但如果你在合并时中遇到它们,那感觉会更糟糕。
然而,深谙这些不太愉快的合作方式并把合并和解决冲突当成习惯,这会增强你在个体间甚至团队中的应变能力。而且,通过使用Android Studio,你会更容易解决这些冲突。记得你启动过主分支上的BroadcastReceiver作为ScheduledReminders 功能的一部分。这个冲突是缘于两个分支内的代码,它包含类似或相同的更改。寻找标红的文件,找到更改视图中的冲突,如图7-47所示。
Figure 7-47. Merge conflicts in the Changes view
【翻译】图7-47 在更改视图中Merge冲突
Right-click and choose Git ? Resolve Conflicts from the context menu, as shown in
Figure 7-48. This will launch the Files Merged with Conflicts dialog box. Resolving confllicts traditionally consists of two parties offering two sources of input; your local changes or yours, and their incoming changes or theirs.
【翻译】右击并选中内容菜单中的Git ? Resolve Conflicts。
如图7-48所示。这会你可以启动Files Merged with Conflict对话框。解决冲突一般需要双方提供两种输入来源,你当地的更改以及yours,他们即将发布的更改以及theirs。
Figure 7-48. Select the Resolve Conflicts option
【翻译】图7-48 选中解决冲突选项
The Android Studio Files Merged with Conflicts dialog box shown in Figure 7-49 is a powerful merge tool for performing three-way file merges and resolving text conflicts. It borrows yours vs. theirs terminology from the traditional merge scenario as it guides you through the merge. The merge tool considers the SetAlarm branch you are rebasing onto as theirs, or the incoming server changes. The master branch you are rebasing from is considered yours, or the local working copy. The Files Merged with Conflicts dialog box starts with a dialog box that allows you to Accept Yours, Accept Theirs, or Merge. The Accept Yours option totally ignores the incoming server file update from the branch you are rebasing onto in favor of the changes from the local working copy branch you are rebasing from and marks the file as resolved. The Accept Theirs option completely replaces your current branch’s local working copy with the incoming server file updates from the branch you are rebasing onto while marking the file as resolved. The Merge option takes you into the three-way merge editor, where you can pull in individual line changes from the incoming server and working copies into the base merge copy while custom merging only the things you need. The base merge copy is the output, or result, of the merge.
【翻译】如图7-49所示的Android Studio Files Merged with Conflicts对话框是一个强大的合并工具,能够完成三方文件归并,解决文本冲突。它会从传统的合并方案中借用yours vs. theirs术语来指导你进行合并。合并工具会把你正在rebese的SetAlarm分支作为theirs或者incoming server changes,把你正在base的主分支当成yours或当地工作副本。Files Merged with Conflicts对话框以一个对话框的形式开启,它能允许你进行Accept Yours, Accept Theirs或合并等操作。Accept Yours选项完全忽视你正在rebase的分支上的incoming server file updata,而是支持你当地工作副本分支上的更改并把这个文件标记为已解决。Accept Theirs选项用你正在rebase的分支上的incoming server file update来完全取代你当前分支上的当地工作副本,并把该文件标记为已解决。合并选项引导你使用三方归并编辑器,当你专门合并你需要的项目时,你可以在这个编辑器上从incoming server和工作副本中把individual line changes 拉入base 合并副本中,其中base合并副本是合并的输出或结果。
Figure 7-49. Merge the ReminderAlarmReceiver
【翻译】图7-49 合并ReminderAlarmReceiver
Click the Merge button to see how this works. The merge editor shown in Figure 7-50 opens.
【翻译】点击合并按钮,看看它如何运行。合并编辑器如图7-50 所示。
Figure 7-50. The Merge editor
【翻译】图7-50 合并编辑器
The Merge editor lines up your working copy and the incoming copy on either side of the Merge Result, which is the editable part of the screen. It is syntax and import aware, which means you can use auto-complete and quick-fix and other keyboard shortcuts as you
edit the local copy. This gives you certain advantages not present in external VCS merge tools. The editor shows both the local working copy and the incoming update, which is marked Changes from Server. These are the changes from the SetAlarm branch that you are rebasing onto. Along the sidebars, you’ll see little double chevrons and Xs next to the changed lines. Clicking a double chevron from either side will include that particular change in your merge result. Clicking the X will omit that particular change. The changes are also color coded, red for a conflict, green for additional lines, and blue for changed lines. In this case, the majority of the file is conflicting.
Since you have only a stub of the class in your local copy on the left, it makes more sense to accept the entirety of the complete implementation from the right incoming changes. Click Cancel and answer Yes to the prompt asking if you want to exit without applying changes.
Click Accept Theirs in the Files Merged with Conflicts dialog box to take the entire incoming server changes. The dialog box lines up the mainfest file next. If you click Merge, you will see that the local working copy has the exact same modification as the incoming server copy, so you can choose either Yours or Theirs. Click the double chevron from the local working copy to accept your change and the X in the incoming copy pane to deny theirs.
Click Save and Finish from the prompt that pops up to complete your merge. Both files will be marked as conflict resolved for Git. If you look in the Changes tool window, you will see files you merged in the Default changelist. Git has paused in the middle of replaying the series of changes onto the ScheduleAlarm branch and is waiting for you to continue.
Go to the main menu and find the VCS ? Git ? Continue Rebasing option, as shown in Figure 7-51. Note you also have the option of either aborting the rebase or skipping this commit while rebasing. If you were in the middle of a complicated merge and realized something was catastrophically wrong, you could click Abort Rebasing and return everything to the state it was in prior to starting the rebase. If you accidentally included a commit
with several conflicts, you also have the option of skipping. Click Continue Rebasing to finish the rebase.
【翻译】合并编辑器会把你的工作副本以及可在界面中编辑的任意一边的合并结果中的incoming副本排成一行。它是syntax和import aware, 这意味着当你编辑本地副本时,你可以使用自动完成、快速修改以及其他键盘快捷方式来进行相关操作。
编辑本地副本合并编辑器也还有一些其他的VCS合并工具中没有的优势。这个编辑器既显示了当地工作副本,也显示了服务器上被标记为更改的incoming update。这些是你正在rebase的来自SetAlarm分支的更改。沿着边栏,你会看到小标签double chevrons和修订行旁边的Xs。从任意一边点击double chevron,这样会让你的合并结果中显示特殊的更改。点击X可以删除这一特殊更改,这些更改也是被彩色编码的。其中红色表示冲突,绿色代指添加行,蓝色指修改行。在这样情况下,大部分文件都是冲突的。
因为你在左侧的当地副本中仅有一小段class, 所以完全接受右侧的incoming changes中的complete implementation将更有意义。点击取消按钮,在询问你“是否在不应用更改的情况下退出”的提示窗口中回答是。
在Files Merged with Conflicts对话框中点击Accept Theirs,进行完整的incoming server更改。接着对话框会把显示文件排列成行。如果你点击合并按钮, 你会看到当地工作副本与incoming server副本拥有完全一致的更改,所以你既可以选择Yours选项,也可以选择Theirs选项。点击当地工作副本上的double chevron,接受your 更改以及incoming copy窗格中的X更改,取消theirs.
从跳出的即时窗口点击保存和完成按钮,完成此次合并。这两个文件在git上都会被标记为“已解决”。如果你查看更改工具窗,你会看到你在默认更改列表中合并过的文件。这时Git已经在ScheduleAlarm分支上的replaying更改序列中暂停运行并等待你的下一步操作。
去主菜单找到VCS ? Git ? Continue Rebasing选项, 如图 7-51所示。注意你既可以中止rebase, 也可以在rebase时跳过这项提交。如果你身陷一项被灾难性错误包围的复杂合并中,,点击AbortRebasing选项,把一切还原到你进行rebase前的状态。如果你在提交时不小心地包含进了几项
冲突,选择跳过选项。点击ContinueRebasing来结束此次rebase.
Figure 7-51. Click the Continue Rebasing menu option
【翻译】图7-51 点击Continue Rebasing菜单选项
The rebase will complete, and a new commit is performed. The Git history will reflect a copy of all the changes from the master following the SetAlarm commit in the timeline. This is shown in Figure 7-52.
【翻译】rebase就这样结束了,一项新提交被完成了。Git历史会在时间轴中显示一个副本,它列出了SetAlarm在提交后的来自母版的所有更改。如图7-52所示。
Figure 7-52. Git history after rebasing and fixing conflicts
【翻译】图7-52 rebase和修改冲突后的Git历史
The master contains commits B and C, supporting ScheduledReminders; commit E, which added the About screen; and commit F from the SetAlarm branch. You also decided you no longer want the ImportantReminders feature with your earlier rebase.
The task of setting the alarm and implementing the actual BroadcastReceiver was done on a separate branch but it now looks like a tag, or milestone, in your timeline. To complete your feature, you need to tie your work from the ScheduleReminders branch to the actual BroadcastReceiver in the SetAlarm branch. Make the following change to connect the listener that invokes the BroadcastReceiver to the TimePickerDialog. You will insert the following code snippet at the end of the else block just before the dialog that we use for Edit Reminder.
【翻译】母版包含了支持ScheduledReminders的提交B和提交C、被添加在About界面上的提交E和SetAlarm分支上的提交F.你也决定你不需要用你之前的rebase方式来设置重要提醒功能。
分别在不同的分支上设置aralm和完成实际的BroadcastReceiver等任务结束了, 但现在它在你的时间轴里看起来就像是一个标签或一个里程碑。为了完善你的功能,你需要把你ScheduleReminders分支上的工作转换到到SetAlarm分支上的 BroadcastReceiver中。作出下列更改,把调用BroadcastReceiver 的Listener关联到TimePickerDialog上。在我们使用编辑提醒器对话之前,把下列代码片段插入到每一个block的结尾部分。
new TimePickerDialog(RemindersActivity.this,listener,today.getHours(),today. getMinutes(),false).show();
Run your project on a device and verify that the feature works. You should now get device notifications when you schedule reminders, as shown in Figure 7-53.
【翻译】在一个设备上运行你的项目并确保这个功能能正常运行。当你设置提醒事项时,你会看到一个设备通知, 如图7-53所示。
Figure 7-53. Notification from a reminder
【翻译】图7-53 来自提醒事项上的通知
You can now push your master branch to the remote Bitbucket host. From the File menu, choose VCS ? Git ? Push. The dialog box in Figure 7-54 opens, giving you the ability to push changes from your local master branch to the remote master branch of your Bitbucket repository. Click the Push button to perform the push.
【翻译】你也可以把你的主分支推送到远程的Bitbucket主机上.从这个文件菜单中, 选择VCS ? Git ?Push.接着图 7-54所示的对话框会打开,它能让你从当地的主分支上推送更改到你Bitbucket版本库上的远程主分支。点击推送标签执行此次推送。
Figure 7-54. Push your changes to Bitbucket
【翻译】图7-54 把你的更改推送到Bitbucket上
Since you are done with the ScheduledReminders and ImportantReminders branches, they can be deleted. Open the Branches dialog box and select both of these branches in turn; click Delete to remove them.
【翻译】删除你已经完成了的ScheduledReminders和ImportantReminders分支。打开分支对话框,轮流选中上面两项分支,点击删除。
Git Remotes
Git remotes are merely copies of a Git repository stored on a remote server and accessible over a network. While you can use them similarly to a traditional client/server-modeled VCS like Subversion, it is better to think of them as publicly accessible copies of your work. You don’t commit to a shared central server in the Git workflow; instead you share your work via pull requests.The pull request is a request from one developer to pull in changes from a public repository under that developer’s profile. Others are free to include individual commits or your entire work at their discretion. You will usually find a main branch, with one or more lead developers responsible for keeping that branch up-to-date with the latest and most valuable features and commits. The leads pull in changes from various contributors by using the entire feature set of Git, which allows the selection, removal, reordering, merging, squashing, and amending of individual commits.
However, pull requests are for advanced Git users. The most common way people begin with Git is by cloning a project from a Git hosting server—downloading an entire copy of the Git repository to work with locally. You continue to make changes and commit them locally, and then finally push these changes back to the remote repository. You can also fetch and merge changes that were pushed by others up to the remote.
Another option is to start with an empty repository locally and build a project. You then push the project to a Git hosting service such as Bitbucket or GitHub and advertise it to be shared with others, or you can make it private and invite others at your discretion. Development continues as in the common approach, with local commits that you push to the remote.
Eventually, contributors fork and add to their remote copies of the project over time as you work, and you will fetch and merge these changes.
【翻译】远程Git
【翻译】远程Git仅仅是储存在远程服务器内、可通过网络连接上的git版本库副本。你会倾向于把它们当作像传统的subversion一样的用户/服务器版本控制系统来使用,但是最好把远程Git当作是你的可被公开访问的工作副本。你并不是在Git工作流中向一个共享的中心服务器提交; 反而你是通过pull申请来共享你的工作。pull申请是一项来自一个开发人员的请求,它请求在那个开发人员头像下的的公共版本库内pull更改,其他人可以在他们的审核下,自由地把个人提交或你的
整项工作列入进来。你通常会发现一个主要分支,它由一个或多个核心开发人员负责用最新的、最有价值的功能和提交来更新。这会导致不同贡献者依靠使用整套的Git的功能设置来把更改拖进Git中, 因为它允许选中、删除、重新排序、合并、粉碎和修补个人提交。
然而, pull请求仅针对Git的高级用户。人们打开git的最常见方式是:先从Git主服务器上克隆一个项目来打开git,然后再下载git版本库上的整个副本来在当地工作。你可以继续作出更改并在当地把它们提交出去,然后让这些更改最终被push回远程版本库中。你也可以提取和合并被其他用户push进远程版本库内的更改。
你的另一个选择是是在一个空的版本库上新建一个项目。然后你可以把这个项目push进git主服务器Bitbucket或GitHub中,并把它广而告之以便他人贡献共享。或者你也可以把它设置成个人私有模式,邀请他人在你的审查下进入。随着你把当地提交push到远程版本库,开发会以常用的方式持续进行下去。
最终,贡献者可以在你工作时为你的项目作分支和添加工作,以便你最终可以提取和合并这些更改。
Pull vs. Push Model
Traditional VCS systems rely on a push model whereby features are worked on by several developers and eventually pushed up to a central server. While this model has worked for years, it is subject to the limitations of a single copy of the master branch becoming corrupt as contributors attempt to merge their changes by using diffs and patch files. Patch files are textual representations of the individual actions taken to change source files; for example, indicating to add these lines, remove those lines, or change this line. Most VCS systems that follow this model manage changes as a series of diffs applied over time.Git follows a distributed pull model treating a project as a shared entity. Because Git allows distributed copies of the master branch, any individual is allowed to commit and update a local copy at any time, which reduces the complexity involved with merging work between contributors. Git also elevates the significance of individual commits, treating them as snapshots of your repository over time. This leaves the tool better adept at managing changes. It also adds the flexibility of managing multiple changes to an individual source file separately. Merges are much more precise and manageable, and the complexity of
combining work is dramatically reduced. For example, a project lead could pull a feature that you’ve implemented in 10 or so commits spread between multiple branches, squash them all into one, amend the message, and organize it in that lead’s personal history before other commits in the master branch, and finally push and publicize it on the remote associated with the project.
【翻译】Pull vs. Push模式
【翻译】传统的版本控制系统依赖于 push模式,通过这种模式,几个开发者使用共同的功能并把它们最终push回一个中心服务器。尽管人们数年来都习惯这种模式,它仍然受限于主分支上的单一副本,因为它在贡献者通过使用diffs和patch文件来尝试合并他们的更改时会奔溃。修补文件是个人操作的文本形式,被用来改变源文件。比如说,它可以被用来表示添加这些行,删除那些行或者更改这行。采用这一模式的大多数版本控制系统在一系列diffs被运用的时候进行更改管理。Git把一个项目作为共同体,遵循分布式的pull模式。因为Git承认主分支上的分布式副本,所以任何人在任何时候都被允许提交和更新当地副本,这一模式降低为贡献者们降低了合并工作的复杂性。Git也会增强个人提交的重要性,并把这些个人提交视为你当地版本库的快照。这会让它更善于管理更改。而且,它还为管理个人源文件上的多重更改增加了灵活性。并合并更加精确且可控,
极大减少了合并工作的复杂程度。比如说,一个项目负责人可能会pull你完成的散布在多个分支上的十多个提交,一次性全部粉碎这些提交并修改信息并在主分支上的其他提交之前在这个负责人的个人历史中规划这项信息。最终,在与这个项目有关的远程版本库中push并公开它。
Summary
This covers the basics of using Git with Android Studio. In this chapter, you’ve seen how to install Git and use it to track changes. We demonstrated how to add your source to Gitand used the Git log feature to see a summary of your commit history. You’ve seen in-depth examples of how branches work like labels pointing to individual commits. The branches can be moved between commits by using relative references or even deleted entirely. We’ve demonstrated how Git history can modify changes that were committed in parallel and line them up serially. We demonstrated a few collaborative scenarios involving multiple branches maturing simultaneously.
【翻译】总结
【翻译】这章囊括了在Android Studio上使用Git的基本方法。通过在这一章,你了解了如何安装Git以及如何用它来追踪更改,如何把你的资源添加到Git上并使用Git的日志功能去一览你的提交历史。你也见到了许多关于分支如何像指向个人提交的标签那样运行的详实例子。这些分支可以通过使用相对参照和彻底删除之间的提交来进行移动。我们向你展示了git历史是如何修改以平行或序列线形方式提交的更改。最后,我们还向你展示了一些包含多重分支共同成熟完善的合作场景。