6. Git - Tools - Notes

6.1 修订版本(Revision)选择

Git 允许你通过几种方法来指明特定的或者一定范围内的提交。了解它们并不是必需的,但是了解一下总没坏处。

单个修订版本

显然你可以使用给出的 SHA-1 值来指明一次提交,不过也有更加人性化的方法来做同样的事。本节概述了指明单个提交的诸多方法。

简短的SHA

只要你提供的那部分 SHA-1 不短于四个字符,并且没有歧义——也就是说,当前仓库中只有一个对象以这段 SHA-1 开头,就可以检索到对应的那次提交。

SHA-1 摘要长度是 20 字节,也就是 160 位。为了保证有 50% 的概率出现一次冲突,需要 2^80 个随机哈希的对象(计算冲突机率的公式是 p = (n(n-1)/2) * (1/2^160))。2^80 是 1.2 x 10^24,也就是一亿亿亿,那是地球上沙粒总数的 1200 倍。

因此,发生SHA-1冲突基本不可能

分支引用

如果你想知道某个分支指向哪个特定的 SHA,或者想看任何一个例子中被简写的 SHA-1,你可以使用一个叫做 rev-parse 的 Git 探测工具。

C:\Users\Administrator\Documents\GitHub\playground>git rev-parse testing
594d17def3fd12e8fe657a4a02c8d50c64a7cda3

引用日志里的简称

在你工作的同时,Git 在后台的工作之一就是保存一份引用日志——一份记录最近几个月你的 HEAD 和分支引用的日志。

你可以使用 git reflog 来查看引用日志:

引用日志里的简称

在你工作的同时,Git 在后台的工作之一就是保存一份引用日志——一份记录最近几个月你的 HEAD 和分支引用的日志。

你可以使用 git reflog 来查看引用日志:

C:\Users\Administrator\Documents\GitHub\playground>git reflog
1270ccc (HEAD -> master) HEAD@{0}: checkout: moving from testing to master
594d17d (testing) HEAD@{1}: checkout: moving from master to testing
1270ccc (HEAD -> master) HEAD@{2}: checkout: moving from testing to master
594d17d (testing) HEAD@{3}: commit: make a change
1270ccc (HEAD -> master) HEAD@{4}: checkout: moving from master to testing
1270ccc (HEAD -> master) HEAD@{5}: commit: initial commit of my project
5d969dc (origin/master) HEAD@{6}: revert: Revert "Create ticgit"
28762a6 (tag: v1.4-lw, tag: v1.4) HEAD@{7}: commit: Create ticgit
b9ca6c4 HEAD@{8}: commit: Update README.md
c1742ee HEAD@{9}: commit (initial): Initial commit

想要看类似于 git log 输出格式的引用日志信息,你可以运行 git log -g

C:\Users\Administrator\Documents\GitHub\playground>git log -g master

祖先引用

另一种指明某次提交的常用方法是通过它的祖先。如果你在引用最后加上一个 ^,Git 将其理解为此次提交的父提交。

提交范围

现在你已经可以指明单次的提交,让我们来看看怎样指明一定范围的提交。这在你管理分支的时候尤显重要——如果你有很多分支,你可以指明范围来圈定一些问题的答案,比如:“这个分支上我有哪些工作还没合并到主分支的?”

双点

最常用的指明范围的方法是双点的语法。这种语法主要是让 Git 区分出可从一个分支中获得而不能从另一个分支中获得的提交。

$ git log master..experiment

指的是可以从experiment获取而不能从master获取的commit

多点

下面三个命令是等同的:

$ git log refA..refB
    $ git log ^refA refB
    $ git log refB --not refA
三点

最后一种主要的范围选择语法是三点语法,这个可以指定被两个引用中的一个包含但又不被两者同时包含的分支。回过头来看一下图6-1里所列的提交历史的例子。 如果你想查看master或者experiment中包含的但不是两者共有的引用,你可以运行

$ git log master...experiment
    F
    E
    D
    C

这种情形下,log命令的一个常用参数是--left-right,它会显示每个提交到底处于哪一侧的分支。这使得数据更加有用。

$ git log --left-right master...experiment
    < F
    < E
    > D
    > C

6.2 交互式暂存

$ git add -i

进入交互式暂存状态

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CxGmY0iz-1586756140836)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200413091416052.png)]

revert是恢复选项

6.3 储藏(Stashing)

经常有这样的事情发生,当你正在进行项目中某一部分的工作,里面的东西处于一个比较杂乱的状态,而你想转到其他分支上进行一些工作。问题是,你不想提交进行了一半的工作,否则以后你无法回到这个工作点。解决这个问题的办法就是git stash命令。

“‘储藏”“可以获取你工作目录的中间状态——也就是你修改过的被追踪的文件和暂存的变更——并将它保存到一个未完结变更的堆栈中,随时可以重新应用。

通过给git stash命令可以储藏工作变更

git stash

你的工作目录就干净了:

$ git status
    # On branch master
    nothing to commit (working directory clean)

使用 git stash list查看现有的储藏记录:

$ git stash list
    stash@{0}: WIP on master: 049d078 added the index file
    stash@{1}: WIP on master: c264051... Revert "added file_size"
    stash@{2}: WIP on master: 21d80a5... added number to log

重新应用你刚刚实施的储藏,所采用的命令就是之前在原始的 stash 命令的帮助输出里提示的:git stash apply。如果你想应用更早的储藏,你可以通过名字指定它,像这样:git stash apply stash@{2}。如果不指明,Git 默认使用最近的储藏并尝试应用它:

$ git stash apply

运行 git stash drop,加上希望移除的储藏的名字可以移除相应的储藏

从储藏中创建分支

$ git stash branch testchanges

6.4 重写历史

很多时候,在 Git 上工作的时候,你也许会由于某种原因想要修订你的提交历史。Git 的一个卓越之处就是它允许你在最后可能的时刻再作决定。你可以在你即将提交暂存区时决定什么文件归入哪一次提交,你可以使用 stash 命令来决定你暂时搁置的工作,你可以重写已经发生的提交以使它们看起来是另外一种样子。这个包括改变提交的次序、改变说明或者修改提交中包含的文件,将提交归并、拆分或者完全删除——这一切在你尚未开始将你的工作和别人共享前都是可以的。

在这一节中,你会学到如何完成这些很有用的任务以使你的提交历史在你将其共享给别人之前变成你想要的样子。

改变最近一次提交

修改最近一次的提交说明

$ git commit --amend
从所有提交中删除一个文件

要从整个历史中删除一个名叫password.txt的文件,你可以在filter-branch上使用--tree-filter选项:

$ git filter-branch --tree-filter 'rm -f passwords.txt' HEAD

如果你想删除所有不小心提交上去的编辑器备份文件,你可以运行类似git filter-branch --tree-filter 'rm -f *~' HEAD的命令。

全局性地更换电子邮件地址

另一个常见的案例是你在开始时忘了运行git config来设置你的姓名和电子邮件地址,也许你想开源一个项目,把你所有的工作电子邮件地址修改为个人地址。无论哪种情况你都可以用filter-branch来更换多次提交里的电子邮件地址。你必须小心一些,只改变属于你的电子邮件地址,所以你使用--commit-filter

$ git filter-branch --commit-filter '
    if [ "$GIT_AUTHOR_EMAIL" = "schacon@localhost" ];
    then
    GIT_AUTHOR_NAME="Scott Chacon";
    GIT_AUTHOR_EMAIL="schacon@example.com";
    git commit-tree "$@";
    else
    git commit-tree "$@";
    fi' HEAD

这个会遍历并重写所有提交使之拥有你的新地址。因为提交里包含了它们的父提交的SHA-1值,这个命令会修改你的历史中的所有提交,而不仅仅是包含了匹配的电子邮件地址的那些。

6.5 使用 Git 调试

Git 同样提供了一些工具来帮助你调试项目中遇到的问题。由于 Git 被设计为可应用于几乎任何类型的项目,这些工具是通用型,但是在遇到问题时可以经常帮助你查找缺陷所在。

文件标注

如果你在追踪代码中的缺陷想知道这是什么时候为什么被引进来的,文件标注会是你的最佳工具。使用了-L选项来限制输出范围在第12至22行

$ git blame -L 12,22 simplegit.rb

二分查找

标注文件在你知道问题是哪里引入的时候会有帮助。如果你不知道,并且自上次代码可用的状态已经经历了上百次的提交,你可能就要求助于bisect命令了。bisect会在你的提交历史中进行二分查找来尽快地确定哪一次提交引入了错误。

bisect允许你在多次提交状态中找出是哪一步出现了问题

通过git bisect start 开始二分察州

$ git bisect start

通过告诉Git

$ git bisect good

or

$ git bisect bad

最终找出哪里出现了问题。

当你完成之后,你应该运行git bisect reset来重设你的HEAD到你开始前的地方,否则你会处于一个诡异的地方:

$ git bisect reset

6.6 子模块

经常有这样的事情,当你在一个项目上工作时,你需要在其中使用另外一个项目。也许它是一个第三方开发的库或者是你独立开发和并在多个父项目中使用的。这个场景下一个常见的问题产生了:你想将两个项目单独处理但是又需要在其中一个中使用另外一个。

子模块初步

通过git submodule add将外部项目加为子模块:

$ git submodule add git://github.com/chneukirchen/rack.git rack
$ git status
    # On branch master
    # Changes to be committed:
    # (use "git reset HEAD <file>..." to unstage)
    #
    # new file: .gitmodules
    # new file: rack
    #

.gitmodules`文件。这是一个配置文件,保存了项目 URL 和你拉取到的本地子目录

$ cat .gitmodules
    [submodule "rack"]
    path = rack
    url = git://github.com/chneukirchen/rack.git

尽管rack是你工作目录里的子目录,但 Git 把它视作一个子模块,

$ git commit -m 'first commit with submodule rack'
    [master 0550271] first commit with submodule rack
    2 files changed, 4 insertions(+), 0 deletions(-)
    create mode 100644 .gitmodules
    create mode 160000 rack

注意 rack 条目的 160000 模式。这在Git中是一个特殊模式,基本意思是你将一个提交记录为一个目录项而不是子目录或者文件。

克隆一个带子模块的项目

这里你将克隆一个带子模块的项目。当你接收到这样一个项目,你将得到了包含子项目的目录,但里面没有文件:

$ git clone git://github.com/schacon/myproject.git

rack目录存在了,但是是空的。

你必须运行两个命令:

git submodule init来初始化你的本地配置文件,

git submodule update来从那个项目拉取所有数据并检出你上层项目里所列的合适的提交:

如果其他提交者修改了子模块并且提交了,你必须再次运行git submodule update

一个常见问题是当开发者对子模块做了一个本地的变更但是并没有推送到公共服务器。然后他们提交了一个指向那个非公开状态的指针然后推送上层项目。当其他开发者试图运行git submodule update,那个子模块系统会找不到所引用的提交,因为它只存在于第一个开发者的系统中。如果发生那种情况,你会看到类似这样的错误:

$ git submodule update
    fatal: reference isn’t a tree: 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
    Unable to checkout '6c5e70b984a60b3cecd395edd5ba7575bf58e0' in submodule path 'rack'

你不得不去查看谁最后变更了子模块

$ git log -1 rack
    commit 85a3eee996800fcfa91e2119372dd4172bf76678
    Author: Scott Chacon <schacon@gmail.com>
    Date: Thu Apr 9 09:19:14 2009 -0700

    added a submodule reference I will never make public. hahahahaha!

上层项目

在 Git 中实现这个的一个好办法是你将每一个子目录都做成独立的 Git 仓库,然后创建一个上层项目的 Git 仓库包含多个子模块。这个办法的一个优势是你可以在上层项目中通过标签和分支更为明确地定义项目之间的关系。

子模块的问题

使用子模块并非没有任何缺点。首先,你在子模块目录中工作时必须相对小心。当你运行git submodule update,它会检出项目的指定版本,但是不在分支内。

切换带有子模块的分支同样也很有技巧。如果你创建一个新的分支,增加了一个子模块,然后切换回不带该子模块的分支,你仍然会拥有一个未被追踪的子模块的目录

$ git checkout -b rack

你将不得不将它移走或者删除,这样的话当你切换回去的时候必须重新克隆它——你可能会丢失你未推送的本地的变更或分支。

最后一个需要引起注意的是关于从子目录切换到子模块的。如果你已经跟踪了你项目中的一些文件但是想把它们移到子模块去,你必须非常小心,否则Git会生你的气。假设你的项目中有一个子目录里放了 rack 的文件,然后你想将它转换为子模块。如果你删除子目录然后运行submodule add,Git会向你大吼:

$ rm -Rf rack/
    $ git submodule add git@github.com:schacon/rack.git rack
    'rack' already exists in the index

你必须先将rack目录撤回。然后你才能加入子模块:

$ git rm -r rack
    $ git submodule add git@github.com:schacon/rack.git rack
    Initialized empty Git repository in /opt/testsub/rack/.git/
    remote: Counting objects: 3184, done.
    remote: Compressing objects: 100% (1465/1465), done.
    remote: Total 3184 (delta 1952), reused 2770 (delta 1675)
    Receiving objects: 100% (3184/3184), 677.42 KiB | 88 KiB/s, done.
    Resolving deltas: 100% (1952/1952), done.

现在假设你在一个分支里那样做了。如果你尝试切换回一个仍然在目录里保留那些文件而不是子模块的分支时——你会得到下面的错误:

$ git checkout master
    error: Untracked working tree file 'rack/AUTHORS' would be overwritten by merge.

你必须先移除rack子模块的目录才能切换到不包含它的分支:

$ mv rack /tmp/
    $ git checkout master
    Switched to branch "master"
    $ ls
    README rack

然后,当你切换回来,你会得到一个空的rack目录。你可以运行git submodule update重新克隆,也可以将/tmp/rack目录重新移回空目录。

6.7 子树合并

子树归并的思想是你拥有两个工程,其中一个项目映射到另外一个项目的子目录中,反过来也一样。当你指定一个子树归并,Git可以聪明地探知其中一个是另外一个的子树从而实现正确的归并——这相当神奇。

首先你将 Rack 应用加入到项目中。你将 Rack 项目当作你项目中的一个远程引用,然后将它检出到它自身的分支:

$ git remote add rack_remote git@github.com:schacon/rack.git

将 Rack 项目当作子目录拉取到你的master项目中。你可以在 Git 中用git read-tree来实现。

$ git read-tree --prefix=rack/ -u rack_branch

当你提交的时候,看起来就像你在那个子目录下拥有Rack的文件

$ git checkout rack_branch
    $ git pull

然后,你可以将那些变更归并回你的 master 分支。

$ git checkout master
    $ git merge --squash -s subtree --no-commit rack_branch

为了得到rack子目录和你rack_branch分支的区别——以决定你是否需要归并它们——你不能使用一般的diff命令。而是对你想比较的分支运行git diff-tree

$ git diff-tree -p rack_branch

或者,为了比较你的rack子目录和服务器上你拉取时的master分支,你可以运行

$ git diff-tree -p rack_remote/master
下拥有Rack的文件

$ git checkout rack_branch
$ git pull


然后,你可以将那些变更归并回你的 master 分支。

$ git checkout master
$ git merge --squash -s subtree --no-commit rack_branch


为了得到`rack`子目录和你`rack_branch`分支的区别——以决定你是否需要归并它们——你不能使用一般的`diff`命令。而是对你想比较的分支运行`git diff-tree`:

$ git diff-tree -p rack_branch


或者,为了比较你的`rack`子目录和服务器上你拉取时的`master`分支,你可以运行

$ git diff-tree -p rack_remote/master

基于SSM框架的智能家政保洁预约系统,是一个旨在提高家政保洁服务预约效率和管理水平的平台。该系统通过集成现代信息技术,为家政公司、家政服务人员和消费者提供了一个便捷的在线预约和管理系统。 系统的主要功能包括: 1. **用户管理**:允许消费者注册、登录,并管理他们的个人资料和预约历史。 2. **家政人员管理**:家政服务人员可以注册并更新自己的个人信息、服务类别和服务时间。 3. **服务预约**:消费者可以浏览不同的家政服务选项,选择合适的服务人员,并在线预约服务。 4. **订单管理**:系统支持订单的创建、跟踪和管理,包括订单的确认、完成和评价。 5. **评价系统**:消费者可以在家政服务完成后对服务进行评价,帮助提高服务质量和透明度。 6. **后台管理**:管理员可以管理用户、家政人员信息、服务类别、预约订单以及处理用户反馈。 系统采用Java语言开发,使用MySQL数据库进行数据存储,通过B/S架构实现用户与服务的在线交互。系统设计考虑了不同用户角色的需求,包括管理员、家政服务人员和普通用户,每个角色都有相应的权限和功能。此外,系统还采用了软件组件化、精化体系结构、分离逻辑和数据等方法,以便于未来的系统升级和维护。 智能家政保洁预约系统通过提供一个集中的平台,不仅方便了消费者的预约和管理,也为家政服务人员提供了一个展示和推广自己服务的机会。同时,系统的后台管理功能为家政公司提供了强大的数据支持和决策辅助,有助于提高服务质量和管理效率。该系统的设计与实现,标志着家政保洁服务向现代化和网络化的转型,为管理决策和控制提供保障,是行业发展中的重要里程碑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值