Android之路

导航

Git详解

    作为软件开发者,对于版本管理应该非常熟悉,常用的版本控制系统有SVN、Git等。之前由于公司项目引入了Gerrit代码审查管理,因此从svn转入了git,虽然都是版本控制,但是git是分布式的,svn则不是,且对应的命令有所区别。开发中也遇到了一些问题,请教了公司的大神(各种命令运用的很溜!我感觉很厉害),觉得自己也要好好学习一下,请大神推荐一些学习网站等。大神说最好的方法就是看git官网以及实践(很赞同,正好本地也安装了Git-Bash)。因此,本文就是结合Git官网学习并练习的一个笔记总结。Git官网-教程  请点击该链接查看原文。

一、前言:

1、版本控制:

    版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。

2、集中式的版本控制系统:

    这类系统,诸如 CVS、Subversion 以及 Perforce 等,都有一个单一的集中管理的服务器,保存所有文件的修订版本,而协同工作的人们都通过客户端连到这台服务器,取出最新的文件或者提交更新。

    缺点:中央服务器的单点故障。即若中心服务器出现问题,则在此期间所有客户端都无法工作;或者中心服务器磁盘损坏,将会导致文件的丢失等。

3、分布式的版本控制系统:

    在这类系统中,像 Git、Mercurial、Bazaar 以及 Darcs 等,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。 这么一来,任何一处协同工作用的服务器发生故障,事后都可以用任何一个镜像出来的本地仓库恢复。 因为每一次的克隆操作,实际上都是一次对代码仓库的完整备份。

二、Git基础:

1、Git的特点:

(1)直接记录快照,而非差异比较;

(2)近乎所有操作都是本地执行(你能愉快地提交,直到有网络连接时再上传);

(3)Git保证完整性;

(4)Git一般只添加数据。

2、Git包含三种状态:

(1)已提交:commited

(2)已修改:modified

(3)已暂存:staged

3、Git项目的三个工作区域概念:

(1)Git仓库:Git 用来保存项目的元数据和对象数据库的地方。 这是 Git 中最重要的部分,从其它计算机克隆仓库时,拷贝的就是这里的数据。

(2)工作目录:对项目的某个版本独立提取出来的内容。 这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘上供你使用或修改。

(3)暂存区域:是一个文件,保存了下次将提交的文件列表信息,一般在 Git 仓库目录中。 有时候也被称作`‘索引’',不过一般说法还是叫暂存区域。

4、Git安装:

    关于Git的安装我就不过多的介绍了,可查看Git-安装 当前主要记录安装后的配置工作。

(1)当安装完 Git 应该做的第一件事就是设置你的用户名称与邮件地址。 这样做很重要,因为每一个 Git 的提交都会使用这些信息,并且它会写入到你的每一次提交中,不可更改:

$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com

再次强调,如果使用了 --global 选项,那么该命令只需要运行一次,因为之后无论你在该系统上做任何事情, Git 都会使用那些信息。 当你想针对特定项目使用不同的用户名称与邮件地址时,可以在那个项目目录下运行没有 --global 选项的命令来配置。
(2)配置编辑器:

git config --global core.editor vim (默认vim)

(3)检查配置信息:

git config --list

git config <key>:检查某项配置
---例如:git config core.editor

  更多配置信息,例如配置 提交模板 等请参看官网Git-自定义配置

(4)关于Git命令的使用帮助:

git help <verb>
git <verb> --help    //默认以网页形式展现
git -<verb>

三、Git操作:

1、获取Git仓库的两种方法:

(1)在现有目录中初始化仓库:进入该目录并执行

$ git init

  如果你是在一个已经存在文件的文件夹(而不是空文件夹)中初始化 Git 仓库来进行版本控制的话,你应该开始跟踪这些文件并提交。 你可通过 git add 命令来实现对指定文件的跟踪,然后执行 git commit 提交:

$ git add *.c
$ git add LICENSE
$ git commit -m 'initial project version'

(2)克隆现有仓库,例如网络上的开源项目。

  Git克隆的是该 Git仓库服务器上的几乎所有数据,而不是仅仅复制完成你的工作所需要文件。

$ git clone <url>
$ git clone <url> <rename>     //自定义本地仓库的名称rename

2、Git中常见的其他操作:

(1)每个文件存在两种状态:未跟踪、已跟踪。

$git add ...            //跟踪新文件或暂存已跟踪文件到暂存区

$git status -s          //几种状态形式

 M testa.java           //文件被修改了但还未放入暂存区
MM Rakefile            //被修改并提交到暂存区后又在工作区中被修改
A  lib/git.rb          //新添加到暂存区
M  lib/simplegit.rb     //被修改了并将修改后的文件放入了暂存区
?? LICENSE.txt          //未跟踪,即新增文件

(2)忽略文件:

  在根目录创建.gitignore文件,用于忽略指定文件(日志文件、临时文件等),即查看状态时不显示,且不会提交等。 .gitignore 的文件,列出要忽略的文件模式。 来看一个实际的例子:

$ cat .gitignore
*.[oa]            //忽略所有以 .o 或 .a 结尾的文件
*~               //忽略所有以波浪符(~)结尾的文件

  文件.gitignore的格式规范如下:

  •  所有空行或者以 # 开头的行都会被 Git 忽略。
  •     可以使用标准的 glob 模式匹配。
  •     匹配模式可以以(/)开头防止递归。
  •     匹配模式可以以(/)结尾指定目录。
  •     要忽略指定模式以外的文件或目录,可以在模式前加上惊叹号(!)取反。

(3)查看已暂存和未暂存的修改:

  git diff:比较工作目录中当前文件和暂存区域快照之间的差异
  git diff --cached:查看已暂存的将要添加到下次提交里的内容.【即仅对untracked的文件有效】
  git diff --staged:同上。(Git1.6.1及以上版本)

(4)提交更新:

  只针对暂存区域提交。因此,在此之前,一定要确认还有什么修改过的或新建的文件还没有 git add 过,否则提交的时候不会记录这些还没暂存起来的变化。这些修改过的文件只保留在本地磁盘。

  上述方法较繁琐,Git提供了跳过暂存区域,直接提交的命令。

$ git commit -a -m "注释"            //-a选项 自动把所有【已经跟踪过】的文件暂存起来

(5)移除文件:

$ git rm :等同于先rm ,再git add;即该操作执行后,该删除文件的状态已经添加至暂存区了.

$ git rm -f :(-f:force强制删除)删除 之前修改过 并且已经放到暂存区域的文件,用于防止误删 还没有添加到快照的数据,这样的数据不能被 Git 恢复。(即本地的也会删除)

$ git rm --cached:从 Git仓库中删除(亦即从暂存区域移除),但仍然希望保留在当前工作目录中。
【因此,若误添加到暂存区,但不包括在本次提交中,则可以使用上述cached移除暂存区】

(6)移动文件:重命名。

$ git mv file_from file_to          //将文件file_from重命名为file_to

(7)打标签:像其他版本控制系统(VCS)一样,Git 可以给历史中的某一个提交打上标签,以示重要。 比较有代表性的是人们会使用这个功能来标记发布结点(v1.0 等等)。

$ git tag -a v1.0 -m "set version 1.0"        //设置标签
$ git tag                               //查看标签
$ git show v1.0                           //查看指定标签对应的提交信息.
$ git tag v1.1-lw                        //轻量标签,不包含任何其他信息
$ git tag -a v1.2 <9fceb02>                //为指定的提交打标签    
$ git push origin v1.5                     //将标签推送至共享服务器,默认不推送
$ git push origin --tags                  //推送多个标签

  注意:在 Git 中你并不能真的检出一个标签,因为它们并不能像分支一样来回移动。 如果你想要工作目录与仓库中特定的标签版本完全一样,可以使用 git checkout -b [branchname] [tagname] 在特定的标签上创建一个新分支。

$ git checkout -b version2 v2.0            //检出标签

(8)签署标签:验证提交是不是真正地来自于可信来源。Git-签署工作

$ gpg --gen-key                    //生成秘钥
$ gpg config --global user.signingkey ...    //配置
$ git tag -s v2.2 -m "signed 2.2 tag"        //-s:签署标签
$ git tag -v v2.2                //验证标签,若能正常工作,则需要签署者的公钥需要在你的钥匙链中.否则提示未找到.

(9)查看历史:

$ git log:列出所有提交记录
$ git log -p <-n>:显示最近n次(n为任意整数)提交的内容差异
$ git log --stat:每次提交的简略统计信息
$ git log --pretty=format:"%h - %an,%ad,%cn,%cd: %s"    //定制要显示的记录格式
%h 提交对象的简短哈希字串 %an 作者(author)的名字 %ad 作者修订日期 %cn 提交者(committer)的名字 %cd 提交日期 其他选项参看截图. $ git log --graph //以图形的形式展示你的分支、合并历史.

(10)撤销操作:

  • 情况一:提交后,发现部分文件忘记提交,可使用下述步骤:
    $ git commit -m 'initial commit'
    $ git add forgotten_file
    $ git commit --amend   

    //文本编辑器启动后,可以看到之前的提交信息。 编辑后保存会覆盖原来的提交信息。

    此时,查看log,只会存在一个提交, 第二次提交将代替第一次提交的结果。需要注意的是,因为修正会改变提交的 SHA-1 校验和。 它类似于一个小的变基 - 如果已经推送了最后一次提交就不要修正它。

  • 撤销暂存的文件:你已经修改了两个文件并且想要将它们作为两次独立的修改提交,但是却意外地输入了 git add * 暂存了它们两个。 如何只取消暂存两个中的一个呢?
    $ git add *
    $ git reset HEAD <file>         //撤销指定文件
  • 撤销暂存区所有文件
    $ git reset HEAD                //其后不指定任何文件
  • 撤销对文件的修改:未提交前
    $ git checkout -- <file>

 

  • 撤销某次提交:
    //paths:回退到某个版本的提交id,前几位即可
    
    $ git reset -- <paths>        //回退到某个版本,且此次提交文件变为未暂存状态
    $ git reset --soft <paths>    //回退到某个版本,只回退了commit的信息,此次提交文件处于暂存状态
    $ git reset --hard <paths>    //彻底回退到某个版本,本地的源码也会变为上一个版本的内容
    例如:git reset -- 25c8e

    另,在彻底回退前,可以先创建备份分支,备份修改代码。前提是在创建备份分支前,在当前分支上已经将修改提交!否则回退后,备份分支中是没有修改的。

    $ git branch old_master
    $ git reset --hard <paths>

    说明

             首先,Git必须知道当前版本是哪个版本,在Git中,用HEAD表示当前版本,也就是最新的提交3628164...882e1e0(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100。

      因此:git reset --hard HEAD^            //回退到上一次提交

    关于撤销修改的操作详询该链接

(11)说明:

  对于上述命令不熟悉的,可以在使用时使用git status,其会告诉你怎么做;另外,在 Git 中任何 已提交的 东西几乎总是可以恢复的。甚至那些被删除的分支中的提交或使用 --amend 选项覆盖的提交也可以恢复(后续讲述)。 然而,任何你未提交的东西丢失后可能再也找不到了。

3、远程仓库的使用:

(1)添加远程仓库:

$ git remote
$ git remote add <reponame> <url>    //reponame:指定仓库的名称
$ git remote -v        // 显示读写远程仓库使用的 Git保存的简写与其对应的URL

例如:

如果你使用 clone 命令克隆了一个仓库,命令会自动将其添加为远程仓库并默认以 “origin” 为简写。

(2)从远程仓库抓取与拉取:

$ git fetch [remote-name]        //访问远程仓库,从中拉取所有你还没有的数据,将数据拉取到你的本地仓库 - 它并不会自动合并或修改你当前的工作。 当准备好时你必须手动将其合并入你的工作。

$ git pull:             //通常会从最初克隆的服务器上抓取数据并自动尝试合并到当前所在的分支。

(3)Git别名:为常用命令创建别名。

$ git config --global alias.co checkout      //此时git co 即可代表 git checkout.

四、Git分支:

1、分支简介与管理

(1)创建分支:实际为一个可以移动的新指针。

//git init时,系统默认创建master分支.

$ git branch testing                 //testing:分支名称;以当前分支创建,但并不切换
$ git branch testing origin/master      //从origin/master分支创建testing分支;默认以当前分支创建新分支.

(2)切换分支:

$ git checkout testing       //切换到testing分支,前提存在testing分支,否则使用下述(4)

补充:

  若首次切换到远程分支(线上分支),会出现类似下述的提示:
    Branch remote1 set up to track remote branch remote1  from XXX.      //即此时remote1是线上分支名称....
  若从未切换至远程分支时,自己创建了同名的remote1本地分支,可能引起混淆,在repo upload时可能出现问题。

(3)HEAD指向当前所在分支,查看使用如下命令:
$ git log --oneline --decorate

$ git log --oneline --decorate --graph --all    //查看项目分叉历史

$ git log --graph                        //查看提交历史图

(4)创建并切换到某个分支:

$ git checkout -b issMain          //创建并切换到issMain分支,同样适用上述(1)

(5)当某个分支已经合并到线上分支后,可删除本地分支。

$ git branch -d hotfix        //hotfix:为解决某个问题时新建的分支

//若出现删除失败,则可能是当前修改未提交或合并等,此时如确定不需要,则可使用 -D 选项强制删除。

实例:假设主分支master  修改分支fixOne  紧急修改分支hotfix。【我自己练习的例子】

情况1:当将修改分支合并到主分支时,可以先在修改分支中提交,然后再merge到主分支,这样可以在修改分支中查看本次修改内容,若不提交而直接merge到主分支,在修改分支中就看不到本次修改。

情况2:当fixOne 与 hotfix都对同一个文件进行修改时,在后合并的会出现合并冲突.解决方法:在分支中解决冲突,再提交合并到主分支.此时单独查看修改分支中冲突文件,则只包含该分支下的修改.而仅有主分支保留所有修改。

(6)查看当前所有分支:

$ git branch 

(7)查看每个分支的最后一次提交:

$ git branch -v

$ git branch -av      //查看分支所跟踪的具体信息

(8)查看哪些分支已经合并或未合并到当前分支

$ git branch --merged 或 $ git branch --no-merged

(9)退出合并

$ git merge --abort 

(10)高级合并:文件test.txt,在master与merge_hot上均进行了修改提交,现需要将merge_hot合并入master分支,如下:

$ git checkout master
$ git merge merge_hot        //出现冲突
此时,
$ git
ls-files -u //获取三个文件版本信息 1:common 2:ours 3:theirs 100644 1babe0cf38ed9f51ae4d8f69bb698d3b5bfd03dc 1 test.txt 100644 52db6bdc08c5c188e796ba8a7deb3d8a61632b7c 2 test.txt 100644 ace7cb9b3a41d2a13e7ed64fa10144bb8f91b093 3 test.txt
然后,将冲突文件的这些版本释放出一份拷贝 $ git show :
1:test.txt > test.common.txt //共同版本(分支叉开时的位置) $ git show :2:test.txt > test.ours.txt //我们的版本(即当前所在分支) $ git show :3:test.txt > test.theirs.txt //他们的版本(将要合并入的分支)

Git和repo管理使用简介

2、远程分支:

(1)获取远程分支信息:

$ git remote show (remote) 或 git ls-remote (remote)

(2)查看所有的跟踪分支信息:

$ git branch -vv
* develop 45229ab [origin/develop: ahead 3] [develop]提交demo.txt
  master  fd68454 [origin/master] [master]fix gradle build error
说明:“ahead
3”表示本地有3个提交还未推送到服务器. 注意:这些数字的值来自于你从每个服务器上最后一次抓取的数据。 这个命令并没有连接服务器,它只会告诉你关于本地缓存的服务器数据

(3)推送本地某个分支到远程仓库,以下几种不同的形式:

$ git push (remote) (branch)
$ git push origin workfix             //将workfix(服务器存在该分支)推送到远程仓库
$ git push origin workfix:somebranch    //将本地的workfix分支推送到远程仓库上的somebranch分支

(4)拉取:

$ git fetch     //服务器上抓取本地没有的数据时,它并不会修改工作目录中的内容。 它只会获取数据然后让你自己合并
$ git pull      //抓取数据并尝试合并,实际上等同于git fetch;紧接着git merge.

(5)删除远程分支:

$ git push origin --delete workfix
--基本上这个命令做的只是从服务器上移除这个指针。 Git 服务器通常会保留数据一段时间直到垃圾回收运行,所以如果不小心删除掉了,通常是很容易恢复的。

(6)变基:另一种解决整合修改的问题的方法。以实例说明。

  假设1:master主分支  exp1、exp2修改分支,冲突文件index.xml; 已经将exp1的修改提交到master分支

  此时可用如下操作将exp2合并到master:  

$ git checkout exp2
$ git rebase master         //变基,出现冲突时,变基终止,解决冲突
然后执行,$ git rebase --continue
$ git add index.xml
//此时仅将该文件加入暂存区,不需要commit 然后执行,$ git rebase --continue
最后,切回master分支,合并exp2,即执行: $ git checkout master $ git merge exp2 至此,完成.

  假设2:master主分支  exp1、exp2修改分支,且均修改了同一文件test.txt。另一种变基,特例。

     此时,希望合并exp1上的修改到master分支并发布,而不合并exp2的修改(exp2上可能需要再测试)。这时,可使用如下步骤仅合并exp1:

$ git rebase --onto master exp2 exp1        //注意顺序,【末尾的为合并的,即exp1】
$ git checkout master
$ git merge exp1        
此时已经完成对exp1的合并.

之后,又决定整合exp2,此时执行下述步骤即可:
$ git rebase master exp2
$ git checkout master
$ git merge exp2
至此,exp1\exp2都已整合到master。

  注意:

  • 无论是通过变基,还是通过三方合并,整合的最终结果所指向的快照始终是一样的,只不过提交历史不同罢了。
  • 不要对在你的仓库外有副本的分支执行变基。==>这点很重要,否则很麻烦具体查看
    总之,只对尚未推送或分享给别人的本地修改执行变基操作清理历史,从不对已推送至别处的提交执行变基操作,这样,你才能享受到两种方式带来的便利。

五、分布式Git:

1、提交代码检查:

(1)检查提交前的空白错误:行尾空白符、Tab、行首空格后跟 Tab 制表符的行为:

$ git diff --check

(2)查看当前分支修改文件状态:

$ git stash           //修改文件前的状态-----储藏
$ git stash pop        //修改后的状态--------应用储藏然后立即从栈上移除

(3)补丁文件:生成patch文件。

$ git diff >diff.patch              //无论几次提交,仅会生成一个patch.

$ git format-patch 节点A 节点B         //生成在两个提交节点间的patch,每次提交对应一个patch文件
$ git format-patch -n <r1>          //-n 表示从节点r1向前的n个节点的提交(包括r1); 节点即为commit-id
$ git format-patch HEAD^             //最近一次提交节点的patch

$ git format-patch <r1>..<r2> -o pathDir    //此时-o 后面指定patch的存放目录,此时所有提交生成的patch均在该目录下。
$ git format-patch <r1>       //某commit以来的修改(不包含该commit);此时并非生成一个patch文件;而是每个提交都会生成一个patch文件。

(4)合并patch:事务性操作。

$ git apply --check  file.patch           //检查patch文件是否能顺利合入当前分支,例如:该patch涉及修改的文件不存在...
$ git apply  file.patch                 //应用patch,patch涉及的文件处于未暂存状态
$ git am < file.patch                 //合入并提交该patch,但是不会有提交记录【不建议使用

(5)查看某个分支上非master分支中的提交。

$ git log featureA --not master          //查看featureA分支上非master分支的提交记录
$ git log -p                        //查看每次提交引入的具体修改
$ git diff master...featureA           //***显示自当前特性分支与 master 分支的共同祖先起,该分支中的工作。

六、Git工具:

 1、查看提交记录,可使用SHA-1的前几个字符(>=7)即可,唯一标识。

$ git show 1c002d

2、引用日志:

$ git reflog                    //近几个月HEAD和分支引用所指向的历史
$ git show HEAD@{5}              //最近5次的提交记录
$ git show HEAD^                //上一个提交记录--即:HEAD的父提交
$ git log master...featureA        //显示在任一分支中的提交,且不在两者共同提交中.

3、储藏:

$ git stash                   //需要切换分支,但又不想因暂时的中断而提交当前工作,将未完成的修改保存到一    
                          //个栈上,而你可以在任何时候重新应用这些改动。此时,执行git status会发现工                        
                          //作目录是干净的,可以轻易切换分支。

$ git stash list                  //查看储藏的内容.
$ git stash apply stash@{2}         //重新应用储藏,可指定哪个储藏,【不指定,默认为最近一次】
$ git stash apply --index          //重新暂存之前暂存的文件
$ git stash drop stash@{0}         //移除储藏
$ git stash --keep-index           //不储藏已经暂存的文件,例:做了几个改动并只想提交其中的一部分,过一会儿再回来处理剩余改动时,这个功能会很有用
$ git stash -u                     //储藏任何创建的未跟踪文件,【默认只储藏已跟踪文件】-u:untracked.
$ git stash branch testchanges     //从储藏创建分支
$ git stash pop                    //应用储藏然后立即从栈上移除

$ git stash --patch                //Git 不会储藏所有修改过的任何东西,但是会交互式地提示哪些改动想要储藏、哪些改动需要保存在工作目录中。

$ git stash clear                  //清除所有缓存的stash。

关于"git stash clear后的恢复工作"请查看.

注意:

(1)git stash:只针对已经add的文件进行储藏,因此若为新增文件,则需要将其加入暂存区;而对于已经存在的文件(tracked)的修改,则无需add;
(2)重新应用储藏后,想撤销本次应用,则可使用如下命令:

    git reset HEAD <file>                 //移出暂存区
    git checkout -- <file>                //撤销修改

(3)应用储藏时,可能存在冲突,此时需手动解决冲突后,再add 、 commit等操作。若不想解决冲突,且不需要本次储藏,则执行上述(2)即可。

 4、清理:

$ git clean                      //移除没有忽略的未跟踪文件
$ git clean -n -d                  //将要移除哪些文件
$ git clean -n -d -x               //-x:包括在.gitignore中的文件
$ git clean -i                     //-i:interactive  交互式运行clean命令.    

  建议慎用上述clean命令,因为移除的是未被跟踪的文件(可能就无法找回);更安全的操作是使用如下命令:

$ git stash --all                //移除前先储藏到栈中.

5、搜索:

$ git grep -n zoom                      //查找zoom匹配的所有行
$ git grep --count zoom                   //统计zoom在每个文件中的匹配数
$ git grep -p zoom *.java                 //在所有.java文件中查找zoom匹配行属于哪个方法或函数
$ git log -S zoom --oneline               //查找zoom何时引入的提交记录.
$ git log -L :method:MainActivity.java    //在MainActivity.java中查找名为method方法的提交记录.若存在多个同名方法,仅显示首个.

6、重写历史:

$ git filter-branch --tree-filter 'rm -r test.txt' HEAD     //从每一个提交中移除一个文件test.txt,无论其是否存在

7、重置:HEAD-->当前分支引用的指针,即上一次提交的快照。(当前分支的上一次提交)

$ git cat-file -p HEAD             //查看HEAD的
$ git ls-tree -r HEAD

$ git reset                     //移动HEAD所在分支
$ git checkout [commit]            //仅移动HEAD本身

8、子模块的使用:

$ git submodule add ...        //将一个仓库添加到当前正在工作的仓库中
添加成功后,使用git status查看,会发现与添加仓库同名的目录及一个.gitmodules文件,该文件记录了项目URL与已经拉取的本地目录之间的映射。

9、 若克隆的是一个包含子模块的项目,则默认会包含该子模块目录,但是为空,需要通过以下命令获取数据:

$ git submodule init              //初始化本地配置信息
$ git submodule update            //拉取子模块数据并检出父项目中列出的合适的提交

可使用如下方法,自动配置并更新子模块: $ git clone --recursive ...

10、打包:

  将git push命令所传输的所有内容打包成一个二进制文件,你可以将这个文件通过邮件或者闪存传给其他人,然后解包到其他的仓库中。

$ git bundle create repo.bundle HEAD master    //repo.bundle:打包后的文件
$ git clone repo.bundle repo            //从打包的文件中克隆,类似URL的克隆

但是,如果在打包时没有包含HEAD引用,则需要在命令后指定一个 -b master 或者其他被引入的分支,否则 Git不知道应该检出哪一个分支。

  最好的方法是,仅打包提交的修改,而非所有代码,使用如下命令:

  (1)首先列出提交区间,例如:在master分支而不在原始仓库中的提交

    $ git log --oneline
    $ git log --oneline master ^origin/master

  (2)打包指定区间的提交:

    $ git bundle create commits.bundle master ^ad117e5

  (3)检查git包是否合法:

    $ git bundle verify     commits.bundle

  (4)查看git包里可以导入哪些分支:

    $ git bundle list-heads   commits.bundle

11、替换:该知识点不好理解,建议结合官网教程Git-替换查看配图学习。

  replace 命令可以让你在 Git 中指定一个对象并可以声称“每次你遇到这个 Git 对象时,假装它是其他的东西”。 在你用一个不同的提交替换历史中的一个提交时,这会非常有用。

  首先获取一个已经存在的仓库,并将其分成两个仓库,一个是最近的仓库,一个是历史版本的仓库,然后我们将看到如何在不更改仓库 SHA 值的情况下通过 replace 命令来合并它们。

(1)查看仓库上的提交记录,以一个简单的仓库为例:

$ git log --oneline    
    
ef989d8 fifth commit
c6e1e95 fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit

(2)将其拆分成两条历史。 第一个到第四个提交的作为第一个历史版本。 第四、第五个提交的作为最近的第二个历史版本。

$ git branch history c6e1e95

$ git log --oneline --decorate

    ef989d8 (HEAD, master) fifth commit
    c6e1e95 (history) fourth commit
    9c68fdc third commit
    945704c second commit
    c1822cf first commit

(3)把这个新的 history 分支推送到我们新仓库的 master 分支

$ git remote add project-history https://github.com/schacon/project-history
$ git push project-history history:master

(4)选择一个点去拆分,commit-tree 命令来创建基础提交.

$ echo 'get history from blah blah blah' | git commit-tree 9c68fdc^{tree}
622e88e9cbfbacfb75b5279245b9fb38dfea10cf

(5)将剩余的历史变基到基础提交之上.

$ git rebase --onto 622e88 9c68fdc    //变基点为我们想留下的第一个提交的父提交(9c68fdc)

(6)为了合并它们,你可以使用 git replace 命令加上你想替换的提交信息来进行替换。 这样一来,我们就可以将 master 分支中的第四个提交替换为 project-history/master 分支中的“第四个”提交。

$ git replace 81a708d c6e1e95

$ git log --oneline master
e146b5f fifth commit
81a708d fourth commit
9c68fdc third commit
945704c second commit
c1822cf first commit

(7)查看详细的提交信息:

$ git cat-file -p 81a708d
tree 7bc544cf438903b65ca9104a1e30345eee6c083d
parent 9c68fdceee073230f19ebb8b5e7fc71b479c0252
author Scott Chacon <schacon@gmail.com> 1268712581 -0700
committer Scott Chacon <schacon@gmail.com> 1268712581 -0700

fourth commit

请记住,81a708d 真正的父提交是 622e882 占位提交,而非呈现的 9c68fdce 提交。

(8)查看引用信息:

$ git for-each-ref

e146b5f14e79d4935160c0e83fb9ebe526b8da0d commit    refs/heads/master
c6e1e95051d41771a649f3145423f8809d1a74d4 commit    refs/remotes/history/master
e146b5f14e79d4935160c0e83fb9ebe526b8da0d commit    refs/remotes/origin/HEAD
e146b5f14e79d4935160c0e83fb9ebe526b8da0d commit    refs/remotes/origin/master
c6e1e95051d41771a649f3145423f8809d1a74d4 commit    refs/replace/81a708dd0e167a3f691541c7a6463343bc457040

这意味着我们可以轻而易举的和其他人分享替换,因为我们可以将替换推送到服务器中并且其他人可以轻松地下载。 也许在历史移植情况下不是很有用(既然每个人都乐意下载最新版本和历史版本,为何还要拆分他们呢?),但在其他情况下仍然很有用。

 七、其他:

    本文更多的是git在上层的应用,即主要是git安装、配置及工作中的使用。而关于git脚本及底层原理都未涉及,作者能力有限,有些东西也看不懂,感兴趣的话可自行查看官网教程学习,主要是下述三部分:

1、关于教程中的第八章自定义Git,本文几乎没有涉及,对于脚本的开发不怎么懂,感兴趣的读者可自行查看官网教程自定义Git

2、将项目从svn转成git,需要借助git svn命令或者迁移等,具体参看第九章Git与其他系统

3、Git底层相关的Git内部原理

4、其他文章推荐:git命令的总结

 

    

posted on 2019-08-01 16:13  Android之路  阅读(321)  评论(0编辑  收藏  举报