《Pro Git》笔记2:Git基础操作

第二章 Git基础

Git基础包括:版本库的创建和获取,文件添加修改提交等基本操作,状态查询,远程版本库管理和同步,打标签。

1.取得项目的Git版本库

基于Git的工作流要以Git版本库为基础,即可以直接创建一个新的本地版本库,也可以将一个已有的远程版本库克隆到本地。

(1)创建新的本地版本库

在一个目录中执行git init命令,会在该目录中建立.git的目录,里面存放了Git需要的所有数据和资源,自然包括一个空的本地版本库。

git init

然后就是向这个本地版本库中存放版本数据了。先使用git add命令添加要追踪的文件,将其纳入版本控制(暂存)。在使用git commit命令提交(将新追踪的文件存入版本库)。这样就创建好了一个项目的本地的版本库。

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

(2)将已有版本库克隆到本地

克隆使用命令git clone。要注意clone是拉取包含了所有修订版本的整个远程版本库到本地,;而checkout只是把本地版本库中的单个修订版本取出来放到工作区里。远程版本库地址可能的协议有git://,http://,https://, SSH (user@server:/path.git)

$ git clone git://github.com/schacon/grit.git          (自动创建grit目录存放版本库)

$ git clone git://github.com/schacon/grit.git   myGrit  (自定义项目目录的名字)

2.将修改保存到版本库

上一篇文章中提到了Git中记录文件变更的三个阶段:修改暂存提交。实际在工作目录中,所有文件都可以分为未追踪已追踪两大类。已追踪文件又有未更新(文件系统状态和git数据不一致)未修改已修改已暂存等状态。其实还有一类会被Git无视的已忽略状态的文件和目录。使用git status命令可以查看文件所处的状态。

git status      只能在Git本地版本库目录(包含.git子目录)或其子目录下执行

《Pro Git》笔记2:Git基础操作

(1)最初始时,工作目录是干净的目录,无未追踪文件,已追踪项目也无任何修改。状态如下:

$ git status
On branch master
nothing to commit, working directory clean

(2)添加新的文件后,显示出未追踪项目

$ echo readme>README

$ git status
On branch master
Untracked files: (还未追踪的项目)
   (use "git add <file>..." to include in what will be committed)
         README
nothing added to commit but untracked files present (use "git add" to track)

 (3)追踪还未版本化的文件,文件从未追踪变为已暂存状态

$ git add README      (如果添加目录,自动递归添加目录下所有项目)

$ git status
On branch master

Changes to be committed:   (已经暂存的项目)
     (use "git reset HEAD <file>..." to unstage)
            new file: README

 (4)修改先前已版本化的文件,文件变成已修改未暂存状态

$echo bbb>benchmarks.rb

$ git status
# On branch master
# Changes to be committed:(已经暂存的项目)
#    (use "git reset HEAD <file>..." to unstage)
#        new file: README
# Changes not staged for commit: (已修改还未暂存的项目)
#    (use "git add <file>..." to update what will be committed)

#    (use "git checkout -- <file>..." to discard changes in working directory) 
#        modified: benchmarks.rb

(5)暂存已修改的文件,也是用git add命令

$ git add benchmarks.rb
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#       new file: README
#       modified: benchmarks.rb

(6)再次修改已暂存的文件,该文件在暂存区会保留一份再次修改前的版本(提交操作的会提交暂存的这一版本),工作目录中同时出现一份再次修改后的版本。

$ echo  ccc>benchmarks.rb
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#         new file: README
#         modified: benchmarks.rb  (暂存前修改过的版本,下次提交时会被提交)
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)

#   (use "git checkout -- <file>..." to discard changes in working directory) 
#         modified: benchmarks.rb  (暂存后再修改的版本,下次提交时不会被提交)

(7)再次暂存修改,文件从已修改变为已暂存状态,并且将暂存区中前一次暂存的版本覆盖掉。

$ git add benchmarks.rb
$ git status
# On branch master
# Changes to be committed:
#    (use "git reset HEAD <file>..." to unstage)
#         new file: README
#         modified: benchmarks.rb

(8)忽略某些对象。(如自动生成的临时文件,编译的中间文件等)。可以在多处配置忽略模式。

方法一:在项目根目录中创建一个.gitignore文件,其中加入要忽略的文件模式即可。(所有空或#开头的行被忽略,支持标准glob模式,/结尾表示目录,!表示忽略指定模式以外的项目)。此.gitignore会提交到版本库,所有人都有效。后面的其他方法只在本地有效。

方法二:全局的.gitignore文件。

方法三:通过git config --global core.excludesfile ~/.gitignoreglobal指定其他忽略文件。

方法四: 编辑项目目录里的.git/info/exclude。

glob模式(shell使用的简化正则表达式):*(0个或多个任意字符),[abc](括号中任何一个字符),?(一个任意字符),[0-9a-zA-Z](范围内任意一个字符)

.gitignore文件示例:

*.[oa]       #忽略.o或.a结尾的文件

!lib.a         #上一条规则中,lib.a除外

*~            #忽略~结尾的编辑器自动保存副本文件

/TODO      #仅忽略根目录下的TODO文件,不包括subdir/TODO

tmp/         #忽略tmp目录下的所有项目

doc/*.txt   #忽略/doc/notes.txt,但不忽略doc/server/arch.txt

(9)比较文件不同版本的具体差异(git diff命令),使用文件补丁格式显示差异。

git diff  [PATH]                   #比较工作目录中版本和暂存版本的差异,(修改了还未暂存的变更)

git diff --cached|--staged [PATH]   #比较暂存版本和上次提交版本的差异,(暂存了还未提交的变更)

(10)提交更新(git commit命令),不使用-a选项时提交前先确认修改内容都已暂存。

git commit                            #这种方式会调用core.editor配置变量中设置的编辑器,让用户输入提交说明,(编辑器中会显示注释掉的提示信息:git status的结果,带-v选项还有git diff的结果,用户输入提交说明并关闭编辑器后所有的注释和空行都被移除)。

git commit  -m  <提交说明>    #提交说明中包含空格时,要用引号引起来

git commit -a -m <提交说明>  #加上-a选项,git会自动把已追踪过的文件修改暂存起来一起提交,不需要手动暂存(git add)。

git commit  -am <提交说明>    #同上

提交后还会回显提交到的分支,新提交的SHA1校验和,改动统计。

$ git commit -m "Story 182: Fix benchmarks for speed"
[master]: created 463dc4f: "Fix benchmarks for speed"
2 files changed, 3 insertions(+), 0 deletions(-)
create mode 100644 README

(11)移除文件(从追踪文件清单和版本库中移除)。从在暂存区删除(即添加删除操作到暂存区),提交后版本库中就删除了。使用git rm同时移除追踪并删除文件。如果使用系统rm命令删除了文件,会出现不一致的情况,仍需要用git rm将其从暂存区删除。下面的<PATH>也可以为glob模式。

git rm <PATH>      #直接删除暂存过的文件会报错。

git rm -f <PATH>  #同时删除暂存的版本,会丢失暂存的修改内容。

git rm --cached <PATH>   #从暂存区和版本库中删除,保留工作目录中的。

$rm grit.gemspec
$ git status
# On branch master
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#       deleted: grit.gemspec

#no changes added to commit (use "git add" and/or "git commit -a")

$ git rm grit.gemspec
rm 'grit.gemspec'
$ git status
# On branch master
# Changes to be committed:
#    (use "git reset HEAD <file>..." to unstage)
#         deleted: grit.gemspec

如果要删除的文件已经被暂存。会提示

$git rm test.txt
error: the following file has changes staged in the index
     test.txt
(use --cached to keep the file, or -f to force removal)

(12)glob模式的扩展。git命令中的文件或目录参数也可以使用glob模式,shell命令行也会自动展开一些通配模式,要注意区分。

git rm log/*.log     #未加反斜杠,shell扩展命令,仅仅删除log目录下的文件,不会递归。
git rm log/\*.log    #加反斜杠,屏蔽shell扩展,git负责扩展,递归删除log目录下的所有.log文件。

git rm \*~             #递归删除当前目录及其子目录中所有~结尾的文件。

(13)移动文件和重命名。git不追踪移动和重命名操作,可以用mv ,git rm, git add三条命令完成重命名或移动(这三个命令可以使用git mv一条命令代替),git会将这些操作的结果都自动识别为重命名。

$ mv README.txt aaa/README
$ git rm README.txt
$ git add aaa/README

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#         renamed: README.txt -> aaa/README

$ git mv README.txt README
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#         renamed: README.txt -> README

3.查看提交历史

(1)输出命令和格式

git log   #按提交时间从新到老列出所有提交记录,默认显示SHA1,作者名字和邮箱,提交时间,提交说明。

-p      按补丁格式额外显示内容差异(git diff)

--stat      额外显示每个文件的变更统计数据和总体变更统计数据

--pretty=oneline(单行显示SHA1和说明)|short|full|fuller|format:"格式占位符"      选择或定制输出内容

格式占位符:作者和提交者不一定相同,提交者可能是版本库管理者,将作者私有分支中提交合并到主分支。

%H SHA1 %h 简短SHA1 %T 树SHA1 %t 树简短SHA1
%P 父对象SHA1 %p 父对象简短SHA1 %an 作者名字 %ae 作者email
%ad 作者修改日期
(可用-date定制格式)
%ar 作者修订日期,多久前 %cn 提交者名字 %ce

提交者email

%cd 提交日期 %cr 提交日期,多久前 %s 提交说明    

--graph    输出能够在一行显示时(使用--pretty选项值为online或format),每行开头显示提交所在分支及其分化衍合图形。

--shortstat  只显示总体变更统计

--name-only   仅在提交信息后显示已修改的文件清单

--name-status  显示新增,修改,删除的文件清单

--abbrev-commit  显示简短SHA1

--relative-date   显示相对时间

(2)输出过滤,过滤条件可以组合

-<数字N>       显示最近的N次提交

--  <PATH>   按提交涉及的文件过滤,放在最后,--用于分隔其他参数,如果无其他参数--可以省略,--与<PATH>直接要有空格

--since|after|until|before = 2.weeks |"2008-01-15" |"2 years 1day 3minutes ago"

--author=<AUTHORNAME>     只显示某个作者的提交

--grep =<DESC>     显示提交说明满足<DESC>条件的提交

--committer=<COMMITTER>  按提交者过滤

--no-merges     还未合并的

例如:显示2008年10月gitster提交的但未合并的涉及test/目录下文件的提交

$ git log --pretty="%h:%s" --author=gitster --since="2008-10-01" --before="2008-11-01" --no-merges -- test/

5610e3b - Fix testcase failure when extended attribute
acd3b9e - Enhance hold_lock_file_for_{update,append}()
f563754 - demonstrate breakage of detached checkout wi
d1a43f2 - reset --hard/read-tree --reset -u: remove un
51a94af - Fix "checkout --track -b newbranch" on detac
b0ad11e - pull: allow "git pull origin $something:$cur

(3)使用图形化工具查看历史,如gitk

(4)git show命令

(5)git blame命令

4.撤销操作

(1)修改最后一次提交。git commit加--amend选项,只修改上一次的提交,不会生成新的提交。

git  commit --amend

git commit --amend -m <新提交说明>

(2)取消已经暂存的文件(git status命令中有提示说明)

git reset HEAD [-- ] <PATH>   #-- 用于分隔其他参数,没其他参数可忽略

(3)取消对文件的修改(git status命令中有提示说明),会丢失还未提交的修改,谨慎使用

git checkout [-- ] <PATH>   #会丢失修改内容,谨慎使用,-- 用于分隔其他参数,没其他参数可忽略

5.远程版本库同步

(1)查看远程版本库

git remote      #只显示远程版本库名(git clone命令会自动创建并使用origin远程库)

git remote -v|--verbose  #显示远程版本库名和地址

origin git://github.com/schacon/ticgit.git

(2)添加远程库

git remote add <远程版本库名> <版本库URL>

(3)抓取远程库数据,不会自动将数据合并到当前工作分支。

git fetch <远程版本库名>  [分支]   #抓取所有远程库独有的数据到本地

git pull <远程版本库名> <分支]>   #抓取远程版本库某分支的数据到本地并合并到工作分支。

git pull     #设置了某个分支跟踪远程库的分支后,可不带参数。git clone自动创建本地master分支跟踪远程maser分支。

git fetch -b   #-b选项表示

(4)推送数据到远程版本库。需要服务器上的写权限。如果别人先推送过更新,需要先抓取到本地进行合并,然后才能推送成功。

git push [远程版本库名] [分支]    #需要远程库的写权限。设置了分支跟踪后,可以不带参数。

(5)查看远程仓库信息

git remote show <远程版本库名>

$ git remote show origin

* remote origin
URL: git@github.com:defunkt/github.git
Remote branch merged with 'git pull' while on branch issues   (pull自动追踪合并的分支)
issues
Remote branch merged with 'git pull' while on branch master  (pull自动追踪合并的分支)
master
New remote branches (next fetch will store in remotes/origin)  (还未同步到本地的分支)
caching
Stale tracking branches (use 'git remote prune')     (同步到本地后在远程被删除的分支)
libwalker
walker2
Tracked remote branches (已追踪的远程分支)
acl
apiv2
dashboard2
issues
master
postgres
Local branch pushed with 'git push'    (push默认推送的分支)
master:master

(6)删除远程版本库

git remote rm <远程版本库名>

(7)重命名远程版本库,重命名后所有远程分支名也会变化(如oldrepo/master变为newrepo/master)

git remote renmae <原远程库名>  <新远程库名>

(8)清理在远程不存在的本地分支

git remote prune

6.打标签

标签是某个提交对象(或者说修订版本)的引用,直接引用提交对象的是轻量级标签,单独创建一个标签对象存储额外信息(校验和,标签名字,email,时间,标签说明等)的是含附注标签。标签可以使用GPG来签署或验证。

(1)列出和显示标签

git tag                           #显示已有标签,按字母顺序排序

git tag -l  'v1.4.2.*'     #过滤标签

v1.4.2.1
v1.4.2.2
v1.4.2.3
v1.4.2.4

git show <标签名>    #轻量级标签,只显示标签引用的提交对象信息,含附注标签还会显示标签对象自身信息(绿字)

tag v1.4
Tagger: Scott Chacon <schacon@gee-mail.com>
Date: Mon Feb 9 14:45:11 2009 -0800
     my version 1.4 (标签说明)

commit 15027957951b64cf874c3557a0f3547bd83b3ff6
Merge: 4a447f7... a6b4c97...
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sun Feb 8 19:02:46 2009 -0800
      Merge branch 'experiment' (提交说明)

(2)新建标签,可以指定版本号给特定版本打上标签

git tag <标签名>  [<版本SHA1>]                                                      #创建轻量级标签

git tag -a <标签名>  [<版本SHA1>]   -m <标签说明>                      #创建含附注标签

(3)分享标签,必须手动推送。其他人克隆或拉取数据同步后就能看到。

git push <远程库名>  <标签名>      #推送指定标签

git push <远程苦命>  --tags        #推送全部标签

(4)签署与验证标签(签署需要私钥,验证需要公钥)

git tag -s <标签名> -m <标签说明>              #签署

git show <标签名>

tag v1.5
Tagger: Scott Chacon <schacon@gee-mail.com>
Date: Mon Feb 9 15:22:20 2009 -0800
my signed 1.5 tag
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (Darwin)
iEYEABECAAYFAkmQurIACgkQON3DxfchxFr5cACeIMN+ZxLKggJQf0QYiQBwgySN
Ki0An2JeAVUCAiJ7Ox6ZEtK+NvZAj82/
=WryJ
-----END PGP SIGNATURE-----
commit 15027957951b64cf874c3557a0f3547bd83b3ff6
Merge: 4a447f7... a6b4c97...
Author: Scott Chacon <schacon@gee-mail.com>
Date: Sun Feb 8 19:02:46 2009 -0800
Merge branch 'experiment'

git tag -v <标签名>                      #验证

object 883653babd8ee7ea23e6a5c392bb739348b1eb61
type commit
tag v1.4.2.1
tagger Junio C Hamano <junkio@cox.net> 1158138501 -0700
GIT 1.4.2.1
Minor fixes since 1.4.2, including git-mv and git-http with alternates.
gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A
gpg: Good signature from "Junio C Hamano <junkio@cox.net>"
gpg: aka "[jpeg image of size 1513]"
Primary key fingerprint: 3565 2A26 2040 E066 C9A7 4A7D C0C6 D9A4 F311 9B9A

7.技巧和窍门

(1)自动完成,输入git命令或选项时,有多个备选时按tab两次显示提示,唯一时按tab自动补全。

bash shell当前用户:Git源码中contrib/completion/git-completion.bash文件复制到~目录,改名为.git-completion.bash,修改.bashrc文件加入source ~/.git-completion.bash。

bash shell系统全局:Git源码中contrib/completion/git-completion.bash文件复制到/opt/local/bash_completion.d目录(Mac)或/etc/bash_completion.d目录(Linux)即可,bash启动时自动加载此目录中内容。

windows用msysGit,Git Bash中默认已配好自动完成脚本。

(2)Git命令别名

git config [--global|--system] alias.<别名>  <原命令或命令参数片段>

git config --global alias.st  status   #可用git st代替git status

git config --global alias.unstage 'reset HEAD -- '   #取消暂存:git unstage fileA 等效于git reset HEAD [--] fileA

git config --global alias.last  'log -1 HEAD'           #查看最后一次提交:git last等效于git log -1 HEAD

上一篇:linux 防火墙操作


下一篇:JVM调优总结(五)-分代垃圾回收详述1