cover

Git基本概念

暂存区(stage、index)
位于.git/index,是介于工作区和版本库的一个中间状态

git对象
位于.git/objects目录,对象类型包括 tree、commit、blob等

Git基础命令

git init 在当前目录创建版本库

git commit

  • -m "message" 提交说明
  • -a all changed file
  • --allow-empty 允许空白提交
  • --amend 对上一次的提交进行修补,不生成新的提交
  • --reset-author 同步提交者信息
  • -c xx 使用xx的提交说明

git grep "content" 查找内容包含content的文件

git rev-parse --git-dir 现在.git目录所在位置

git rev-parse --show-toplevel 显示工作区根目录

git config git配置命令

(./git/config) > (~/.gitconfig (--global) )> (/etc/config (--system) )

git log 查看日志

  • --pretty=fuller
  • --pretty=oneline

git status -s 显示精简的状态信息

  • 位于第一列的字符M的含义是:版本库中的文件与处于中间状态——提交任务(提交暂存区,stage)中的文件相比有改动。

  • 位于第二列的字符M的含义是:工作区当前的文件与处于中间状态——提交任务(提交暂存区,stage)中的文件相比有改动。

git rm --cached <file> 直接从暂存区删除文件

git clean -fd 清理未跟踪的文件和目录

git clean -nd 测试上面命令会删除哪些文件

git ls-files --with-tree=HEAD^ 查看版本库中的文件列表

git add -u 将(被版本库追踪的)本地文件的变更(修改、删除)全部记录到暂存区中。

git add -A 将工作区中的所有改动及新增文件添加到暂存区

git cherry 显示领先提交(未被推送到上游跟踪分支中)

GIT重置命令

reset命令可以改变.git/refs/heads/master下分支的引用,而不是永远指向最新的提交ID。

reflog(.git/logs/refs/heads/master)命令恢复

重置引用后提交历史信息会丢失,这时可以使用reflog命令查看操作日志,以便进行恢复操作

git reflog show master |head -5 显示master分之最近五次操作日志

git reflog -1 显示HEAD分支最近一次操作日志

reset命令的两种用法

用法一:git reset[-q][<commit>][--]<paths>

用法二:git reset[--soft|--mixed|--hard|--merge|--keep][-q][<commit>]

  1. 第一种用法不回重置引用和工作区,而是用commit下的文件替换暂存区文件,相当于撤销git add <paths>的操作,其中commit可以省略,默认为HEAD

  2. 第二种则会重置引用,但会根据不同的参数从而影响工作区或者暂存区,其中commit也可以省略,默认为HEAD

  3. 使用参数--hard 工作区,引用、暂存区全部替换为commit

  4. 使用参数--soft 只更改引用,工作区和暂存区不影响
  5. 使用参数--mixed(不写默认) 只更改引用和暂存区,不影响工作区

GIT检出命令

checkout命令可以改变HEAD指针的引用,而不是永远指向refs/heads/master

改变HEAD指针到某一commit后,会处于detached-head(分离头指针)状态,这时如果有新的提交,最好merge到分支

checkout命令的三种用法

用法一:git checkout[-q][<commit>][--]<paths>

用法二:git checkout[<branch>]

用法三:git checkout[-m][[-b|--orphan]<newbranch>][<startpoint>]

  1. 第一种用法(包含了路径<paths>的用法)不会改变HEAD头指针,主要是用于指定版本的文件覆盖工作区中对应的文件。如果省略<commit>,则会用暂存区的文件覆盖工作区的文件,否则用指定提交中的文件覆盖暂存区和工作区中对应的文件。
    例如用某个提交覆盖本地工作区:git checkout 提交ID -- .

  2. 第二种用法主要是用于切换分支,所以分支的切换其实就是HEAD头指针的引用切换

第一种用法的<commit>是可选项,如果省略则相当于从暂存区(index)进行检出。这和重置命令大不相同:重置的默认值是HEAD,而检出的默认值是暂存区。因此重置一般用于重置暂存区(除非使用--hard参数,否则不重置工作区),而检出命令主要是覆盖工作区(如果<commit>不省略,也会替换暂存区中相应的文件)。

GIT恢复进度

git stash 保存工作进度,会分别对暂存区和工作区进行保存

git stash list 显示进度列表

git stash pop[--index][<stash>] 恢复最新一条保存进度

如果不使用任何参数,会恢复最新保存的工作进度,并将恢复的工作进度从存储的工作进度列表中清除。

如果提供<stash>参数(来自于git stash list显示的列表),则从该<stash>中恢复。恢复完毕也将从进度列表中删除<stash>。

选项--index除了恢复工作区的文件外,还尝试恢复暂存区。这也就是为什么在本章一开始恢复进度的时候显示的状态和保存进度前的略有不同。

git stash save "message..." 保存进度时候指定说明

使用参数--patch会显示工作区和HEAD的差异,通过对差异文件的编辑决定在进度中最终要保存的工作区的内容,通过编辑差异文件可以在进度中排除无关内容。

使用-k或--keep-index参数,在保存进度后不会将暂存区重置。默认会将暂存区和工作区强制重置。

git stash apply[--index][<stash>] 除了不删除恢复的进度之外,其余和git stash pop命令一样。

git stash drop[<stash>] 删除一个存储的进度。默认删除最新的进度。

git stash clear 删除所有存储的进度。

git stash branch<branchname><stash> 基于进度创建分支

GIT文件忽略

git文件忽略需要在根目录新建.gitignore文件,作用范围是其所处的目录及其子目录

并且无法使用add添加,只对未加入跟踪的文件有效

查看被忽略的文件 git status --ignored -s

Git忽略语法

  • 忽略文件中的空行或以井号(#)开始的行会被忽略。

  • 可以使用通配符,参见Linux手册:glob(7)。例如:星号(*)代表任意多字符,问号(?)代表一个字符,方括号([abc])代表可选字符范围等。

  • 如果名称的最前面是一个路径分隔符(/),表明要忽略的文件在此目录下,而非子目录的文件。

  • 如果名称的最后面是一个路径分隔符(/),表明要忽略的是整个目录,同名文件不忽略,否则同名的文件和目录都忽略。

  • 通过在名称的最前面添加一个感叹号(!),代表不忽略。

下面的文件忽略示例,包含了上述要点

  • #这是注释行--被忽略
  • **.a # 忽略所有以.a为扩展名的文件。
  • !lib.a # 但是lib.a文件或目录不要忽略,即使前面设置了对*.a的忽略。
  • /TODO # 只忽略此目录下的TODO文件,子目录的TODO文件不忽略。
  • build/ # 忽略所有build/目录下的文件。
  • doc/*.txt # 忽略文件如doc/notes.txt,但是文件如doc/server/arch.txt不被忽略。

GIT拣选命令

git cherry-pick 命令需提供一个提交ID作为参数,然后在当前HEAD上重放此提交,形成不管是内容还是提交说明都一样的提交

GIT变基命令

命令格式:git rebase--onto<newbase><since><till>

变基操作的过程:

(1)首先会执行git checkout切换到<till>。

因为会切换到<till>,因此如果<till>指向的不是一个分支(如master),则变基操作是在detached HEAD(分离头指针)状态进行的,当变基结束后,还要对master分支执行重置以实现变基结果在分支中生效。

(2)将<since>..<till>所标识的提交范围写到一个临时文件中。

还记得前面介绍的版本范围语法吗,<since>..<till>是指包括<till>的所有历史提交排除<since>及<since>的历史提交后形成的版本范围。

(3)将当前分支强制重置(git reset--hard)到<newbase>。相当于执行:git reset--hard<newbase>。

(4)从保存在临时文件中的提交列表中,将提交逐一按顺序重新提交到重置之后的分支上。

(5)如果遇到提交已经在分支中包含,则跳过该提交。

(6)如果在提交过程遇到冲突,则变基过程暂停。用户解决冲突后,执行git rebase--continue继续变基操作。或者执行git rebase--skip跳过此提交。或者执行git rebase--abort就此终止变基操作切换到变基前的分支上。

命令git rebase --onto C E^ F 相当于把E到F之间的所有提交嫁接到C上

GIT交互式变基

命令格式:git rebase -i <since><till>

交互式变基就是在变基命令的基础上,添加了-i参数,在变基的时候进入一个交互界面。使用了交互界面的变基操作,不是自动化变基转换为手动确认那么没有技术含量,而是充满了魔法。

执行交互式变基操作,会将<since>..<till>的提交悉数罗列在一个文件中,然后自动打开一个编辑器来编辑这个文件。可以通过修改文件的内容设定变基操作,实现删除提交、将多个提交压缩为一个提交、更改提交的顺序,以及更改历史提交的提交说明等。

例如,下面的界面就是针对当前DEMO版本库执行的交互式变基时编辑器打开的文件:

pick b3af728 ignore object files.
pick 3488f2c move.gitignore outside also works.
pick 48456ab add hello.h
pick b6f0b0a modify hello.h

#Rebase d71ce92..b6f0b0a onto d71ce92
#
#Commands: #p,pick=use commit
#r,reword=use commit,but edit the commit message
#e,edit=use commit,but stop for amending
#s,squash=use commit,but meld into previous commit
#f,fixup=like "squash",but discard this commit's log message
#x<cmd>,exec<cmd>=Run a shell command<cmd>,and stop if it fails
#
#If you remove a line here THAT COMMIT WILL BE LOST.
#However,if you remove everything,the rebase will be aborted.

参考文件中的注释,可以通过修改动作名称,在变基的时候执行特定操作。

  • 前四行默认的动作都是pick,即应用此提交。

  • 动作reword,或者简写为r。在变基时会应用此提交,但是在提交的时候允许用户修改提交说明。这个功能在Git 1.6.6之后开始提供,对于修改历史提交的提交说明非常方便。对于老版本的Git没有reword动作,可以使用edit动作。

  • 动作edit,或者简写为e。也会在变基时应用此提交,但是会在应用后暂停变基,提示用户使用git commit--amend执行提交,以便对提交进行修补。当用户执行git commit--amend完成提交后,还需要执行git rebase--continue继续变基操作。用户在变基暂停状态下可以执行多次提交,从而实现把一个提交分解为多个提交。edit动作非常强大,对于老版本的Git没有reword动作,可以使用edit动作实现相同的效果。

  • 动作squash,或者简写为s。该提交会与前面的提交压缩为一个。

  • 动作fixup,或者简写为f。类似动作squash,但是此提交的提交说明被丢弃。这个功能在Git 1.7.0之后开始提供,老版本的Git还是使用squash动作吧。

可以通过修改变基任务文件中各个提交的先后顺序,进而改变最终变基后提交的先后顺序。 可以修改变基任务文件,删除包含相应提交的行,这样该提交就不会被应用,进而在变基后的提交中被删除。

精简历史

使用git commit-tree命令直接从该目录树创建提交 $echo "Commit from tree of tag A."|git commit-tree A^{tree} 然后使用变基操作将A之后的提交嫁到到新提交上 $git rebase--onto 8f7f94b A master

反转提交

当我们进行多人开发时,修改历史提交显然会出问题,但是对于已经push了的提交怎么办呢,这时候可以反转提交。反向提交一次,产生一个新的提交

命令如下 git rever HEAD 相当于讲HEAD的提交反向再提交一次。

GIT里程碑

git tag 显示当前版本库里程碑列表

git tag -n1 在显示里程碑的时候同时显示说明,使用-n<num>参数,显示最多<num>行里程碑的说明。

git tag-l shaofan* 只显示名称和通配符相符的里程碑。

git log --oneline --decorate 在查看日志时使用参数--decorate可以看到提交对应的里程碑及其他引用。

git describe 使用命令git describe将提交显示为一个易记的名称。这个易记的名称来自于建立在该提交上的里程碑,若该提交没有里程碑则使用该提交历史版本上的里程碑并加上可理解的寻址信息。

若提交没有对应的里程碑,但是在其祖先版本上建有里程碑,则使用类似<tag>-<num>-g<commit>的格式显示。

其中<tag>是最接近的祖先提交的里程碑名字,<num>是该里程碑和提交之间的距离,<commit>是该提交的精简提交ID。

--dirty参数如果工作区有文件修改,将会通过后最-dirty显示出来

创建里程碑

用法1:git tag<tagname>[<commit>]
用法2:git tag-a<tagname>[<commit>]
用法3:git tag-m<msg><tagname>[<commit>]
用法4:git tag-s<tagname>[<commit>]
用法5:git tag-u<key-id><tagname>[<commit>]

用法1是创建轻量级里程碑。

用法2和用法3相同,都是创建带说明的里程碑。其中用法3直接通过-m参数提供里程碑创建说明。

用法4和用法5相同,都是创建带GnuPG签名的里程碑。其中用法5用-u参数选择指定的私钥进行签名。

创建里程碑需要输入里程碑的名字(<tagname>)和一个可选的提交ID(<commit>)。

如果没有提供提交ID,则基于头指针HEAD创建里程碑。

删除里程碑

git tag -d tagname 删除本地里程碑 git push origin :tagname 删除远程里程碑

远程版本库

git remote add origin <url> 注册远程版本库

git remote set-url origin <url> 修改远程版本库地址

git remote rename origin origin1 重命名远程版本库

git remote rm origin 删除远程版本库

git remote update 更新所有注册的远程版本库

补丁

git format-patch -s HEAD~3..HEAD 最近三次提交生成补丁文件

cat *.patch|git am 应用补丁

支付宝扫码打赏 微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章

杨少凡's Picture
杨少凡

殿堂级渣洼工程师,现居重庆,目前就职于人和集团电商部。

Chongqing「重庆」 http://shaofan.org