git整理

git特点:
1- 直接记录快照,而非差异比较。以快照流的方式对待数据。对所有文件制作一个快照,保存这个快照的索引。如果文件没有改动,git只是简单保留一个链接指向之前存储的文件。
2- 近乎所有操作都是本地执行,所以很快。例如svn如果断网了就无法提交。

 

git三种状态:
已提交(committed): 修改进入了本地数据库中
已修改(modified): 修改了,但未保存到数据库中
已暂存(staged): 将修改的文件快照放入暂存区等待提交

 

git三个区域概念(Working tree, staging area, and Git directory):
git仓库目录(.git):git用来存储项目元数据和对象数据库的地方
工作目录: git仓库的压缩数据库中提取出来的某个版本
暂存区: 是一个保存了待提交文件的信息,放在git仓库目录中

 

HEAD的概念:
HEAD就是指向当前分支的最后一个提交的指针
HEAD可以简写成@。    HEAD~N表示顺着自己这一脉(主线,git log --graph的左边)上溯N个提交。  HEAD^表示上溯一个提交(等效于HEAD^1,这里的1表示主线,2表示被合并的提交<假设存在,git log --graph的右分支>), HEAD^^^表示主线上溯3个提交(等效于HEAD^^^1)。

 

获取帮助:
git help <verb>     #例如git help config
git <verb> --help
man git-<verb>

 

获取一个仓库(repository):
途径1: 克隆远程仓库。 执行git clone <remote_repo> [directory]会从服务器仓库上拉取源码文件的所有版本
途径2: 初始化一个本地仓库。在有源码的目录中执行git init命令初始化一个仓库,在目录下会生成.git仓库目录。此时没有任何文件被跟踪


基本流程:
1-修改文件
2- git add <pathspec>...                     # 跟踪<pathspec>指定的目录或文件,也就是将它们纳入版本控制。同时这些文件也进入了暂存区,等待提交。
3- git commit -m "初始化工程"           #提交到本地git仓库(也就修改的快照进入.git仓库目录)

注意 git add 命令是个多功能命令。1-可以用它开始跟踪新文件; 2-把已跟踪的文件放到暂存区; 3-还能用于合并时把有冲突的文件标记为已解决状态...等功能。
           git commit是将暂存区的快照提交到git仓库
           所以,执行git add后,修改的快照进入了暂存区待commit,如果此时又修改了文件,那么修改还在工作区中,需要再次git add才能将新的修改放入暂存区。

 

配置:
git配置文件可以使用git config命令来读写:
       1.   /etc/gitconfig 作用于系统级 git config 加 --system选项时读写此文件
       2.  ~/.gitconfig 或 ~/.config/git/config 作用于当前用户 git config 加 --global选项时读写此文件
       3.  当前仓库目录下的.git/config 作用于当前仓库目录对应的仓库 工作目录是该仓库,且git config 不加参数时,读写此文件
每一个级别覆盖上一级别的配置,所以 .git/config 的配置变量会覆盖 /etc/gitconfig 中的配置变量。

重要命令
git config --list                         #列出当前配置
git config <key>                      # 查看某项配置,例如 git config core.editor
git config <key> <value>        # 修改某项配置,例如: git config --global core.editor vim

 

远程仓库操作:

git clone -b master https://a.cn/x/y.git      # 只克隆master分支(对于很大的仓库或网速很慢时挺有用的)
git remote -v                                            # 查看远程分支, 加-v参数不但显示远程仓库短名字,还显示它的长名字。 origin是git clone给远程仓库默认生成的短名字,长名字就是那串长长的url:https://a.com/foo/bar
git remote show origin                             # 查看远程仓库origin的所有远程分支,这条命令可以查看本地分支跟踪的是哪个远程分支。(设置跟踪参考下面git push -u的说明)
git branch -r                                            # 列出远程仓库的所有分支以及远程仓库的默认分支是哪个(例如origin/HEAD->origin/master)。 “git ls-remote [远程仓库短名字]” 也是类似功能的命令
git remote add <远程短名字> <url>         # 关联远程仓库(远程仓库存在的情况下才执行这条命令)。一个本地仓库可以关联多个远程仓库
git fetch origin  dev:Dev                          #  从远程仓库origin下载数据,指定远程仓库的dev下载到对应本地仓库Dev。语法: git fetch   <远程短名>  [远程分支][:本地分支]   直接执行git fetch会从默认追踪的远程分支下载
git pull                                                     # 是git fetch 和git merge的组合,参数指定方式参考上面的git fetch,我通常不适用git pull , 而是git fetch,然后再git merge。
git push origin  LB:rb                              # 推送本地分支LB到远程仓库origin的rb分支。如果远程仓库origin没有rb分支,则会在远程origin下新建一个rb分支。如果直接执行git push那么就将本地分支推送到默认的远程仓库。如果本地仓库关联多个远程仓库,可以直接执行git push fooRep来指定将本地分支的变更推送到远程仓库fooRep下。如果推送的时候,提示没有对应的上游分支可以增加-u选项(--set-upstream选项的缩写)来建立对远程分支的跟踪,一旦使用-u来跟踪远程分支了,后面直接git push,不用跟其他参数了。这里我们执行git remote show origin就会看到本地的LB追踪了远程仓库origin的rb分支
git push --all origin                                 # 不管本地是否存在对应的origin远程分支,都会将本地的所有分支都推送到远程主机.
git rename origin gitee_foo                    # 把远程仓库名origin重命名为gitee_foo
git remote rm gitee_foo                         # 删除远程仓库,也可以: git push origin --delete dev //假设远程仓库短名是origin
注意: 一般而言,dev、debug之类的分支是不需要推送到远程仓库的,一般是把这些分支合并到master分支后,推送master到远程仓库

 

分支操作:
git branch                                                      #查看分支 -v 或 -vv会显示详细信息
git branch --merged                                      #查看所有已合并的分支, 同理 --nomerged查看所有未合并的分支
git branch <branchName>                            #创建分支
git branch <brName> <commitID>                #以某个commitID来创建分支,非常有用
git checkout <branchName>                         #切换分支, 加-b参数标示创建并切换分支
git checkout origin/br0                                  #对于远程clone下来的仓库origin,切换到它的br0分支
git checkout -b <local-br> <remote>/<br>     #创建一个与远程分支remote/br相对应的本地分支  #针对特定标签建分支
git checkout -b <brName> <tag>                  #针对特定标签建分支
git merge <branchName>                             #合并分支到当前分支。 通常合并分支时,git一般使用”Fast forward”模式,禁用FF模式,需要加参数--no-ff ( 非FF合并后的历史有分支,能看出来曾经做过合并,而FF看不出来)
git branch –d <branchName>                       #删除分支-D表示强制
git branch -u <remote>/<brName>               # 设置已有的本地分支来跟踪一个刚刚拉取下来的远程分支。 -u的长选项格式是--set-upstream-to。 此时@{u}或@{upstream}是<remote>/<brName>的快捷方式。所以git merge @{u}相当于git merge <remote>/<brName>
git push origin --delete branch1                  #删除远程分支, 也可以写成 git push origin :branch1 

 注意master分支应该是非常稳定的,一般不在上面干活。在dev分支上干活,然后将稳定了的dev分支合并到master分支。团队协作是各个成员将自己分支不断合并到dev分支。

 

工作进度隐藏:
git stash save "stash_comment"       #保存完成一半的工作, 此时git status提示是干净的。
git stash list                                       #列出已经隐藏的git栈
git stash apply stash@{N}                 #恢复到stash N
git stash clear                                   #清除缓存的stash
git stash pop                                     #将stash从git栈中弹出
git drop stash@{N}                           #删除某个stash
git stash show stash@{N}                #查看某个stash

 

比较差异:
git diff   [<path>...]                                         #使用默认对比工具来比较
git difftool   [<path>...]                                   #使用第三方工具比较差异, 例如BeyondCompare。关于将beyondCompare用于git,参考另一篇文章 
git diff/difftool [file]                                         #对比工作区和暂存区的差别(git add之前的)
git diff/difftool --staged [file]                           #对比暂存区和上次commit的差别
git diff/difftool  <commit-id> <commit-id>       #比较两个版本(用commit-id指定)的差异
git diff/difftool HEAD  [file]                              #比较工作区和最后一次commit的差异
git diff/difftool  master  ReadMe.txt                #比较当前分支和master分支的ReadMe.txt文件的差异 
git log dev ^master                                        # 比较dev分支有,而master分支没有的提交
git log master..dev                                        # dev比master多了哪些提交? ..可以理解为from->to
git log master...dev                                       # 不知道谁的提交多,只是想比较有哪些提交差异.加--left-right 参数可以显示提交所属的分支是哪个(例如git log --left-right master...dev 的<箭头表示master的)
git whatchanged <file>                                 # 查看某个文件的变更的详细提交记录,简单记录可以使用git log --pretty=oneline  <file>。 查看完后,可以git show <commit-id> [file]或者git difftool <commit-id1> <commit-id2> [file]来查看具体变更
git blame <file>                                             # 显示文件的每一行最后变更的commit id

 

撤销修改 / 版本回退 :
git  checkout  [commit-id] --  ReadMe.txt proto.c          #从暂存区(如果指定了commit-id的话,则从该次提交id中恢复)中恢复文件到工作区。也就是执行add之前反悔了。这里的"--"表示选项的结束,如果没有任何选项,可以省略 "--"
git  reset  --soft  <commit-id>                     # HEAD移动到 commit-id 指定的那个提交(不是针对单个文件或目录,所以参数中不能跟路径),也可以用HEAD~N的方式来指定重置到前N个版本。
git  reset --hard  <commit-id>                    #HEAD暂存区工作区都重置到commit-id指定的提交(不是针对单个文件或目录,所以参数不带路径)。这个有点危险,如果误操作,只能通过git reflog 查一下历史操作的commit-id才能恢复
git reset  --mixed  <commit-id>   [path]      #HEAD暂存区都重置到commit-id指定的提交,工作区不变, --mixed是默认选项,参数可以带路径(可以针对单个文件或目录执行重置)
我测试的结果:   --soft是只重置HEAD指针, 工作区和暂存区不变。 不能带路径。
                           --hard是HEAD、暂存区和工作区都重置(危险操作) 。不能带路径。
                           --mixed是重置HEAD和暂存区(默认参数)。 工作区不变。可以带路径,但是带路径会有warning

git revert  <commit-id>         #revert和reset的区别是,revert是将旧版本变成一个新的提交.  可以revert常规commit也可以revert分支合并的commit, 后者需要-m <1|2> 来指定保留哪个分支,1表示当前分支
例如下面revert合并的commit:
--A------B-----C------M----X----Y(revert)
   \-----a-----b-------/
如果当前处于上面分支X状态(此时上面分支有AaBbCX的提交), 如果Y处执行git revert -m 1 M的CommitID    则上面的分支只有ABCX的提交,(也就是丢弃了ab的提交)
                                                                                          如果Y处执行git revert -m 2 M的CommitID    则上面的分支只有AabX的提交(也就是丢弃了BC的提交). 注意这条命令是在Y处执行,而非上一条命令执行完后执行

revert注意的地方,可以到https://segmentfault.com/a/1190000012897697看例子

 

修改已完成的提交(commit后,可以多次修改该commit):
例如:
git add proto.c
git commit -m '修正proto.c的bug' #突然发现漏了proto.h和gen_id.c,忘了移除tmp.txt,于是执行:
git add proto.h gen_id.c
git rm tmp.txt
git commit --amend '修正proto.c和gen_id.c的bug' #此时git log --stat 只能看到修改后的提交

 

删除文件:
git rm <file> ; git commit -m 'xxxx'                   #删除工作区和暂存区文件,并且提交
git rm --cached <file> ; git commit -m 'xxx'      #删除暂存区文件,并提交。此时工作区文件还在,这是版本库不再跟踪它了。

  

查看提交历史:
git log -3 #查看最近三次提交
git log --after/before='1999-09-09'          #查看1999-09-09前/后的提交。 指定时间可以使用类似"1year"、“8days”之类的。 --after等同--since,--before等同于--until
git log --author/--committer=<name>      #按作者/提交者查看,注意作者和提交者的区别
git log --grep=<pattern>                          #按正则搜索注释
git log hello.c                                          # 查看修改了hello.c的commit,查看针对某个路径的commit,如果有很多选项时,可以使用 -- 标示选项结束: liru
git log --graph                                         #形象显示commit log
git log --stat                                            #显示commit 历史涉及的文件
git show --stat [commitID]                      #显示某个commit涉及的文件变更
git log --pretty=format:%h" "%an" "%s    #显示短hash、作者、注释(空格分隔)。更多%号格式参考git lot help
git log --pretty=oneline                           #单行显示commit历史
git log  --  server.c                                  # 查看 server.c 的提交记录

 

标签:
git  tag                                                                                                   # 查看已有标签
git  tag  -l  'v1.*'                                                                                     # -l是小写的L,只列出 v1.* 的版本号, 批配处v1.0 v1.1 v1.2...
git  tag   v1.0                                                                                         # 打一个轻量级标签, 轻量级标签是对某个提交的引用。不指明commit-id的情况下,默认引用HEAD
git  tag  -a   v2.0  -m '这是v2.0附注标签的说明'                                     # 打上一个附注标签,-a是的a是annoted的首字母。附注标签是一个仓库中的独立对象。它有自身的校验和信息,以及标签说明。
git  tag  -s    v2.1 -m '这是v2.0附注标签的说明'                                     # 打上一个GPG签名的附注标签。 -s是signed的首字母. 使用git show v2.1会看到GPG签名
git  show  v2.0                                                                                       # 查看标签v2.0的详情
git  tag  -v  v2.1                                                                                     # 验证含有GPG签名的标签(keyring中需要有GPG公钥)
git  tag  v1.2   df1796d00a50a5567fac0b7d689402942943e01d         # 给df1796d00a50a5567fac0b7d689402942943e01d这个提交打轻量标签
git tag -a v2.3 -m '忘记打标签了'                                                           # 给df1796d00a50a5567fac0b7d689402942943e01d这个提交打附注标签
git  push origin  v2.3                                                                             # 将标签推送到远程仓库origin。(默认情况下git push是不会推送标签的,所以需要专门推送标签,标签才能体现在远程仓库上)
git  push  origin  --tags                                                                          # 将所有标签推送到远程仓库

 

------------------------------------ 注意力分割线 --------------------------------------

我做的小测试:
mkdir x; cd x
git init
git remote add ts2 https://gitee.com/xxx/test2
git fetch ts2                                       # 抓取的副本在本地的工作空间是看不到文件的。ps: 可以git fetch ts2 dev 只fetch dev分支
git checkout -b dev ts2/dev              #此时就可以看到ts2/dev对应的的本地dev分支了。此时执行 ls -l 就能看到工作空间有文件了
上面的最后两步可以这么玩:
git fetch ts2 dev:dev      #fetch ts2的dev分支,并在本地创建dev分支
git checkout dev            #切换到本地dev分支,此时就能看到远程的ts2/dev分支在本地对应dev分支的工作空间文件了

git checkout -b dev2      #建立本地dev2分支
git push -u ts2 dev2      #把本地分支dev2 推送到远程分支ts2上,结果在gitee服务器上看到了dev2分支

posted on 2019-03-27 18:29  进取有乐  阅读(481)  评论(1编辑  收藏  举报

导航