设为首页 收藏本站
查看: 1789|回复: 0

[经验分享] Git使用方法(一)[转]

[复制链接]

尚未签到

发表于 2018-1-15 15:06:15 | 显示全部楼层 |阅读模式
  Linux项目开始后,绝大多数的Linux内核维护工作都花在了提交补丁和保存归档的繁琐事物上(1991——2002年间)。到2002年,整个项目组开始启用分布式版本控制系统BitKeeper来管理和维护代码。到2005年的时候,开发BitKeeper的商业公司同Linux内核开发社区的合作关系结束,他们收回了免费使用BitKeeper的权力。这就使得Linux开源社区不得不开发了自己的版本控制软件Git。
DSC0000.gif

  其他系统在每个版本中记录着各个文件的具体差异
DSC0001.gif

  Git保存每次更新的文件快照
  这是Git与其他版本控制系统的主要差别,其他版本控制系统节省了磁盘空间,但增加了计算量;Git是都保存了,因为磁盘原来越便宜。
  在保存到Git之前,所有数据都要进行内容的校验和(checksum)计算,并将此结果作为数据的唯一标识和索引。Git使用SHA-1算法计算数据的校验和,通过对文件的内容或目录的结构计算出一个SHA-1哈希值,作为指纹字符串。该字符由40个十六个进制字符(0-9及a-f)组成,看起来就像是:
DSC0002.gif

  首先安装git,我是在ubuntu下,所以输入命令:
  $sudo apt-get install git-core
  OK!此时应该git成功安装,查看git版本:
  $git --version
DSC0003.gif

  一:获取项目的git仓库:
  1)从当前目录初始化:
  $git init
  创建了一个空的git仓库:
DSC0004.gif

  如果这个git仓库已经初始化过了,则提示exist:
DSC0005.gif

  如果成功创建一个空的git仓库可以看到在当前目录下出现一个.git目录,这个就是仓库了!
DSC0006.gif

  现在偷窥一下.git目录下都有什么:
DSC0007.gif

  2)从现有仓库克隆:
  克隆仓库的命令为git clone [url]。比如,要克隆Ruby语言的Git代码仓库Grit,可以用下面的命令:
  $git clone git://github.com/schacon/grit.git
  这时在当前目录下创建一个名为“grit”的目录,其中内含一个.git目录,并从同步后的仓库中拉出所有的数据,取出最新版本的文件拷贝。如果想自己指定目录的名字:
  $git clone git://github.com/schacon/grit.git mygrit
  获得Linux2.6内核源码:
DSC0008.gif

  如果使用git clone --bared则会只clone .git仓库,而不会clone working directory和staging area。下面是对比,linux-kernel是使用git clone得到的,my-linux是使用git clone --bared得到的
DSC0009.gif

  二:新加文件到index中,使得git可以跟踪它:
  git有3个区域,分别是:

  • working directory
  • staging area
  • repository
DSC00010.gif

  任何一个git里的文件都有三种状态:

  • 已修改(修改了某个文件,但是没有提交)
  • 已暂存(把修改的文件放在下次提交时要保存的清单中)
  • 已提交(该文件已经安全地保存在本地数据库中了)
    DSC00011.gif

基本的Git工作流如下:

  • 在工作目录中修改某些文件
  • 对这些修改了的文件作快照,并保存到暂存区
  • 提交更新,将保存在暂存区域的文件快照转储到git目录中
DSC00012.gif 工作目录下面的所有文件都不外乎这两种状态:已跟踪或未跟踪。已跟踪的文件是指本来就被纳入版本控制管理的文件,在上次快照中有它们的记录,工作一段时间后,它们的状态可能是未更新的,已修改或者已放入暂存区。而所有其他文件都属于未跟踪文件。它们既没有上次更新时的快照,也不在当前的暂存区里。初次克隆某个仓库时,工作目录中的所有文件都属于已跟踪文件,且状态为未修改。使用git status检查当前文件状态:$git status DSC00013.gif   说明没有跟踪任何文件
  用vim修改一下工作目录下的main.c文件,再将文件git add到staging area,然后:
  $git add .
DSC00014.gif

  git add+要跟踪文件名,可以看到这里多了一个index文件,这就是那个staging area。再次运行git status
DSC00015.gif

  可以看到main.c文件已经被跟踪,并处于暂存状态。
  三:提交
  然后再git commit进行提交,把数据提交到git仓库中:
  $git commit -m "this is first commit"
  注意这里通过-m 选项加一个注释,这样你就可以提交你的数据到git仓库了,也可以把两个步骤合并文一个步骤:
  $git commit -a -m "this is first commit"
  git有两个配置文件,一个在$HOME下,是全局的,设置时加--global,另一个在仓库配置文件里。
  $git config
  设置全局的:
DSC00016.gif

  本地的:
DSC00017.gif

  Git使用方法(二)
  
  一:使用.gitignore忽略某些文件
  
  文件.gitignore的格式规范如下:

  • 所有空行或以注释符号#开头的行都会被Git忽略
  • 可以使用标准的glob模式匹配
  • 匹配模式最后跟反斜杠(/)说明要忽略的是目录
  • 要忽略指定模式以外的文件或目录,可以在模式前加惊叹号(!)取反
  一般时候我们总会有一些文件无需纳入Git的管理,也不希望他们总出现在未跟踪文件列表。通常都是些自主生成的文件,像是日志或者
  编译过程中创建的等等。我们可以创建一个.gitignore的文件,列出要忽略的文件模式,来看一个例子:
   DSC00018.gif
  这里忽略了工作目录下的.test文件,以.o或.a结尾的文件。
   DSC00019.gif
  如果不使用.gitignore,可以看到,显示.test文件未跟踪,下面添加.gitignore文件
DSC00020.gif

  可以看到工作目录很干净的。
  如果使用git下载Linux内核源码,你可以在工作目录下看到.gitignore文件,cat .gitignore,截了一段:
   DSC00021.gif
  
  二:git diff 生成patch
  
  git-diff列出自己本地的tree中已修改,但却未commit的改动,这也是产生patch的方式。注意,使用git-diff产生的patch都应该在patch(1)时
  指定-p1,或者直接使用git-apply打补丁。
DSC00022.gif

  选项:
  --clour diff 语法高亮
  --ignore-space-at-eol 忽略行尾的whitespace
  --ignore-space-change 忽略行尾的whitespace,并且认为所有的whitespace都是一样的
  --ignore-all-space 比较两行的时候,完全忽略whitespace。这样,即使是一行有很多whitespaces,另一行文字一样但是没有whitespace,
  git也认为这两行内容一致。
   DSC00023.gif
  这里介绍一下patch文件格式:补丁头
  补丁头是分别由---/+++开头的两行,用来表示要打补丁的文件。---开头表示旧文件,+++开头表示新文件。
  一个补丁文件中的多个补丁
  一个补丁文件中可能包含以---/+++开头的很多节,每一节用来打一个补丁。所以在一个补丁文件中可以有好多个补丁。
  块
  块是补丁中要修改的地方。它通常由一部分不用修改的东西开始和结束。他们只是用来表示要修改的位置。他们通常以@@开始,结束于
  另一个块的开始或者一个新的补丁头。
  块的缩进
  块会缩进一列,而这一列是用来表示这一行是要增加还是要删除的。
  块的第一列
  +号表示这一行是要加上的
  -号表示这一行是要删除的
  没有加号也没有减号表示这里只是引用的而不需要修改
  
  三:git apply打补丁
  git-apply相当于patch(1)命令,不过git-apply专门用来apply那些用git-diff生成的补丁
  选项:
  --check 不真正打补丁,而只是检查补丁是否能完美的打上
  -v verbose模式
  -R reverse模式,也就是拉出这个补丁来
  
   DSC00024.gif
  
  
  四:git log 查看提交历史记录
  
  运行git log:
DSC00025.gif

  git会按提交时间列出所有的更新,最近的更新排在最上边。每次更新都会有一个SHA-1校验,作者的名字和电子邮件地址,提交时间,最
  后一个段落显示提交说明。
  选项说明:
  -p 按补丁格式显示每个更新之间的差异
  --stat 显示每次更新的文件修改统计信息
  --shortstat 只显示--stat中最后的行数修改添加移除统计
  --pretty 使用其他格式显示历史提交信息。可用的选项包括online,short,full,fuller和format。
  下边是加-p选项,按补丁格式查看每个更新之间的差异
  $git log -p
DSC00026.gif

  Git使用方法(三)
  
  在Git中提交时,会保存一个提交(commit)对象,它包含一个指向暂存内容快照的指针,作者和相关附属信息,以及一定数量(也可能没有)指向
  提交对象直接祖先的指针:第一次提交是没有直接祖先的,普通提交有一个祖先,由两个或多个分支合并产生的提交则有多个祖先。现在假设
  工作目录下有3个文件,准备将他们暂存后提交。暂存操作会对每一个文件计算校验和(即SHA-1哈希字符串),然后把当前版本控制的文件快照
  保存到Git仓库中,并将校验和加入暂存区域。当使用git commit新建一个提交对象前,Git会先计算每一个子目录(本例中就是就是项目根目录)
  的校验和,然后在Git仓库中将这些目录保存为树(tree)对象。之后Git创建的提交对象(commit),除了包含相关提交信息以外,还包含着指向这
  个树对象(项目根目录)的指针,如此他就可以在将来需要的时候,重现此次快照的内容。
DSC00027.gif

  这个是提交一次后仓库里的数据
DSC00028.gif

  多次提交后Git仓库数据
  Git中的分支,其实本质就是个指向commit对象的可变指针。Git会使用master作为分支的默认名字。在若干次提交后,你其实已经有了一个
  指向最后一次提交对象的master分支,它在每次提交的时候都会自动向前移动。
  一:git branch
  
   DSC00029.gif
  经过多次提交仓库中的情况如上,master指向最新的commit,那么怎样创建一个新的分支呢,可以使用git branch+分知名,这里用
  git branch testing,就创建了一个基于master的分支。
  $git branch testing
   DSC00030.gif
  HEAD是一个引用,指向正在使用的分支。
   DSC00031.gif
  进行查看:
   DSC00032.gif
  下面切换到新的分支:
   DSC00033.gif
  $git checkout testing
DSC00034.gif

  使用git branch可以查看当前都有哪些branch,前面有*的表示,当前所在的branch。
   DSC00035.gif
  可以看到,此时master与testing都指向同一个commit,这里的9831*******,一共是20个字节,40个十六进制的字符,这个就是将文
  件放到暂存区时产生的哈希字符串,它作为文件的名字,这里使用git cat-file -t 查看object的类型,这里至少用前四个字符。
   DSC00036.gif
  现在切换到testing分支,修改工作目录下的main.c文件,然后提交,再次看HEAD的指向,发现testing中的HEAD已经指向新的
  commit了。
   DSC00037.gif
   DSC00038.gif
  现在对master分支的main.c文件进行修改:
   DSC00039.gif
   DSC00040.gif
  可以看到此时master指向的commit已经变化,形成上图的分支。
  git branch -a 列出所有分支,包括remote和local branches
  git branch -r 列出remote branches
  git branch -d new-branch 删除new-branch
  git branch -D new-branch 强制删除new-branch
  
  二:git merge
  
   DSC00041.gif
   DSC00042.gif
   DSC00043.gif
  从上边几张图可以看出先是基于master创建了分支iss53,此时它们指向同一个commit,之后iss32分支进行了commit,然后基
  于master创建了新的分支hotfix,并进行了commit。现在要把hotfix分支合并到master分支中。
   DSC00044.gif
  git merge + 要merge的branch,这样就可以把branch merge到当前branch上了。先git checkout master,然后git merge hotfix,
  这样hotfix branch就可以merge到master分支上了,然后git branch -d hotfix对hotfix分支进行删除。这里的merge其实是比较简
  单的,由于master分支指向的commit是hotfix分支指向的commit的parent,所以直接移动master指针到hotfix指向的commit就可以了。
  
   DSC00045.gif
  git branch --merge查看哪些分支已被并入当前分支
  git branch --no-merge查看哪些分支没有被并入当前分支
   DSC00046.gif
  
  下面这个是three-way merge
   DSC00047.gif
   DSC00048.gif
  这里要merge c4和c5,此时Git会用两个分支的末端(C4和C5)和他们的共同祖先(C2)进行一次简单的三方合并计算。Git可以
  自己裁决哪个公共祖先才是最佳合并基础。
  
   DSC00049.gif
  
  
  三:git checkout
  
  git checkout branch-name 切换到branch-name
  git checkout master 切换到master
  git checkout -b new-branch master 从master建立新的new-branch,并同时切换过去new-branch
  git checkout -b newbranch 由现在的分支为基础,建立新的branch
  git checkout -b newbranch origin 由origin的基础,建立新的branch
  git checkout filename 还原档案到Repository状态
  git checkout HEAD 将所有档案都checkout出来(最后一次commit的版本),注意,若有修改的档案都会被还原到上一版
  git checkout xxxx 将所有档案都checkout出来(xxxx commit的版本,xxxx是commit的编号前四位),注意,若有修改的档案
  都会被还原到上一版
  四:git show
  
  可以使用git show加上commit名称来显示更详细的commit信息:

  也可以使用git show加分支名称,也可显示分支信息:

  使用HEAD字段可以代表当前分支的头(也就是最近一次commit):
  $git show HEAD
  每一次commit都会有“parent commit”,可以使用^表示parent:
  $git show HEAD^ 查看HEAD的父母的信息
  $git show HEAD^^ 查看HEAD的父母的父母的信息
  $git show HEAD~5 查看HEAD上溯5代的信息
  有的时候git merge会产生双父母,比如three-way merge的时候,这种情况这样处理:
  $git show HEAD^1 查看HEAD的第一个父母
  $git show HEAD^2 查看HEAD的第二个父母
  
  五:git archive
  可以把当前版本(HEAD所处的位置)给export出来
  使用git describe可以查看当前的version
  $mkdir ../linux-2.6.11
  $git archive -v v2.6.11 | (cd ../linux-2.6.11/ && tar xf -)
  $head -4 ../linux-2.6.11/Makefile

  从本地git仓库中提取某个版本的kernel:
  $git archive -v v2.6.11 | (cd ../linux-2.6.11/ && tar xf -)
  -v表示--verbose,注意'v2.6.11'可以是git tag -l列出的tags中的一个,也可以是其他Rev>  这里的“&&”类似“;”不过是有区别的,如果每个命令被一个分号“;”所分隔,那么命令会连续的执行下去。如果每个命令
  被“&&”号分隔,那么这些命令会一直执行下去,如果中间有错误的命令存在,则不再执行后面的命令,没错则执行到完为止。
  这里的“-”作用是把前边的输出作为这里的输入
  导出最新的kernel:
  $git archive -v HEAD | (cd ../linux-HEAD/ && tar xf -)
  或者打成tar包:
  $git archive -v --format=tar v3.0 | bzip2 >../linux-3.0.tar.bz2

  Git使用方法(四)
  
  一:git remote
  
  远程仓库是指托管在网络上的项目仓库,可能会有好多个,其中有些你只能读,另外有些可以写。同他人协作开发某个项目时,需要管理这些远程仓库,以便推送或拉取数据,分享各自的工作进展。管理远程仓库的工作,包括添加远程库,移除废弃的远程库,管理各式远程库分支,定义是否跟踪这些分支,等等。
  在克隆完某个项目后,至少可以看到一个名为origin的远程库,Git默认使用这个名字来标识你所克隆的原始仓库:
  $git remote
  orgin
  也可以加上-v选项(-v为-verbose的缩写,取首字母),显示对应的克隆地址:
  
  添加远程仓库,可以指定一个简单的名字,以便将来引用,运行git remote add [shortname] [url]:
  
  
  使用git remote show [remote-name]查看某个远程仓库的详细信息:
  
  它告诉我们,运行git push时缺省推送的分支是什么(最后两行)。它还显示了有哪些远程分支还没有同步到本地(第六行的caching分支),哪些已同步到本地的远端分支在远程服务器上已被删除(Stale tracking branches下面的两个分支),以及运行git pull时将自动合并哪些分支(前4行中列出的issues和master分支)。
  
  远程仓库的删除和重命名
  可以用git remote rename命令修改某个远程仓库的简短名称,比如想把AA改成BB,可以这么运行:
  $git remote AA BB
  $git remote
  origin
  BB
  移除远程仓库git remote rm命令:
  $git remote rm BB
  $git remote
  origin
  
  二:git fetch
  
  从远程仓库抓取数据,使用git fetch [remote-name][branch-name]。
  
  
  三:git pull
  
  
  从远程仓库分支中获得更新,git push [remote-name] [branch-name],pull命令包含两个操作:从远端分支中取出改动,然后合并到当前分支中。相当于git fetch+ git merge。
  当git clone之后,直接git pull它会自动匹配一个正确的remote url,因为在.git/config文件里配置了[branch "master"]下面的内容:
  

  • git处于master这个branch下时,默认的remote就是origin
  • 当在master这个branch下使用指定remote和merge的git pull时,使用默认的remote和merge
  $git pull
  
  
  四:git push
  
  如果把本地的master分支推送到origin服务器上(),可以运行下面命令:推送数据到远程仓库使用git push [remote-name] [branch-name],
  $git push origin master
  只有在所克隆的服务器上有写权限,或者同一时刻没有其他人在推数据,这条命令才会如期完成任务。如果你在推数据前,已经有其他人推送了若干更新,那你的推送操作就会被驳回。你必须先把他们的更新抓取到本地,并到自己的项目中,然后才可以再次推送。
  
  
  五:git reset
  
  使用git reset撤销改动,git reset HEAD^删除最近的commit,选项:
  --mixed staged与commited都会清除,但是modified不会清除
  --hard modified,staged,commited都会清除
  --soft commited被清除,modified,staged还在
  reset是将当前head的内容重置,不留任何痕迹。
  Sets the current head to the specified commit and optionally resets the index and working tree to match。
  git reset --hard HEAD~4
  会将最新的4次提交全部重置,就像没有提交过一样。
  
  使用--mixed选项,如果你不添加选项,默认使用的是--mixed选项:
  
  这里的&#8220;changed but not updated&#8221;表示文件被modify,但是没有stage,你有两个选择,一个是stage,git add<file>...,另一个选择是撤销这次修改git checkout --<file>...
  
  使用--hard选项:
  
  
  使用--soft选项:
  
  这里的&#8220;Changes to be committed&#8221;表示已经modified并且stage,但是没有commit,你可以使用git reset HEAD <file>...进行unstage,或者使用git commit进行commit。
  有的时候想要修改提交信息使用git commit --amend
  此命令将使用当前的暂存区快照提交。如果刚才提交完没有作任何改动,直接运行此命令的话,相当于有机会重新编辑提交说明,而所提交的文件快照和之前的一样。

  这里将之前的commit信息&#8220;second&#8221;改为&#8220;this is second commit&#8221;。
  在git中,除非你运行了git-gc --prune,否则历史是永远不会被擦除的,你可以随意恢复到任何历史状态。下面是一个恢复被git-reset --hard擦除了的commit的例子:
  使用git-reflog查看历史:

  
  六:git revert
  
  git revert只是修改了commit,修改后再次提交。
  git revert与git reset的区别:

  • git reset是还原到指定的版本上,这将扔掉指定版本之后的版本
  • git revert是提交一个新的版本将需要revert的版本的内容再反向修改回去,版本会递增,不影响之前提交的内容

  Git使用方法(五)
  
  一:git tag
  
  git tag列出已有的标签:
  
  使用特定的搜索模式列出匹配的标签:
  
  获得某个版本的源码:
  $mkdir ../linux-2.6.11
  $git archive -v v2.6.11 | (cd ../linux-2.6.11/ && tar xf -)
  $head -4 ../linux-2.6.11/Makefile

  git使用的标签有两种类型:轻量级的(lightweight)和含注释的(annotated)。新建含注释的标签会产生一个标签对象,而轻量级标签不会产生标签对象。
  轻量级的标签建立:
  $git tag v1.0
  这样就会给当前的commit打上v1.0这个标签。

  此时这个tag是一个引用,不是对象。
  含注释的标签建立:
  $ git tag -a [name] -m [&#8220;xxxx&#8221;]

  建立含注释的标签会产生一个标签对象:

  可以看到在创建标签后对象数增加了一个。
  
  
  二:git bisect
  
  如果一个项目到某一个版本发现一个错误,你还知道之前某个版本是好的,那么可以用git bisect来定位最先出现bug的版本。可以:
  git bisect start
  git bisect bad 现在这个版本是有bug的
  git bisect good good_commit good_commit是好的版本,你可以用tag表示,也可以用那20byte的前2个byte表示
  
  
  我的这个意思是,如果数大于等于5就是bug,这里找到了第一个大于等于5的commit。
  三:git format-patch
  
  git format-patch -2 -o ~/patch/
  git format-patch是用于把当前的git目录中的commit生成的patch文件,并组织成UNIX mailbox的邮件格式。--cc后指定的是邮件的抄送接收人。-2表示只处理最后两次commit
  
  四:git send-email
  
  git send-email --to xxx@xxx --to xxx@xx --cc  xxx@xxx --bcc xx@xx ~/patch
  git send-email用于把刚才生成的patch文件直接以email的方式发送出去,要用这个命令需要保证正确配置了SMTP服务器的相关信息。用git直接生成patch邮件发送到邮件列表是一个很方便的方式,而且可以保证发出来的邮件有比较统一的格式,方便别人来审阅你的patch。
  git config file
[sendmail]

  smtpencryption = tls
  smtppass       = xxxx
  smtpserver     = smtp.gmail.com
  smptuser = kernellwp@gmail.com
  smtpserverport = 587

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-435353-1-1.html 上篇帖子: Git回滚远程版本 下篇帖子: 如何导入另一个 Git库到现有的Git库并保留提交记录
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表