git使用和理解之一(不含分支)

0、前言

  • Workspace:工作区
  • Index / Stage:暂存区
  • Repository:仓库区(或本地仓库)
  • Remote:远程仓库

工作区和暂存区
  我们写代码的地方就是工作区,代码写完后,我们可以把他提交到暂存区,提交到暂存区后,我们可以对自己的代码进行更改,修改文件内容,删除或者增加文件,只需一个git checkout xx即可让暂存区内容覆盖当前工作区的内容,或者说还原!

暂存区(暂时存用)和本地仓库
  我们可以把暂存区的内容提交到我们的本地仓库,此时会在仓库中生成一个快照,我们可以为这个快照打一个TAG信息,比如这个快照叫"完成了UI部分"这样,提交后暂存区中的内容就会被清空,此时我们可以调用reset指令,制定某个快照,然后还原到暂存区

工作区和本地仓库
  我们可以直接走checkout某个版本的指令,直接让工作空间还原成某个本地仓库中的某个快照

本地仓库和远程仓库

  我们可以将本地的某个快照push推送到远程仓库,push时可能还需处理一些冲突;也可以从拉取远程仓库到本地,也会有冲突出现。

工作区和远程仓库

  这两者的协作一般是pull,即同步远程仓库的代码到工作空间而已~

.git隐藏文件夹各种文件的含义

 .gitignore的文件  commit的时候会忽略,push pull的时候都会忽略

git中文件的状态     Tracked(已跟踪)    Untracked(未跟踪)   Staged(暂存)    Unmodified(未修改)    Modified(修改)

 TrackedUntracked区分依据:该文件是否已经加入版本控制?当我们在项目中新增一个文件,这个文件此时就处于Untracked状态!

git add指令将该文件加入暂存区,那么此时该文件此时处于Tracked状态,又或者说这个文件已经被我们的版本控制系统所跟踪了,而且他处于Staged(暂存)状态!

把暂存区的文件commit后,此时该文件处于Unmodified(未修改)状态;此时假如我们编辑下该文件,文件又会变成Modified(修改)状态,接着git add又处于Staged(暂存)状态,然后commit...

 1、在master分支操作的五部曲(本地master到远端origin的master分支) --》这里的origin指的是远端的主机名字,可以自定义,默认为origin。

  ①  git status       ---    查看工作区对比上一个commit之后的工作区修改状态  

  ②  git add -A      ---    把工作区的内容提交到暂存区  也就是图中的Index中(-A代表的是全部,如果不想提交全部,那么换成指定的文件名)

  ③  git commit -m "备注的内容"   ---  把Index暂存区的内容提交到本地仓库中。

  ④  git pull    ---  拉去远端默认分支上的代码,并主动与本地仓库的内容进行合并,此处要注意conflict出现。

  ⑤  git push   ---   把本地仓库的代码推送到远端默认仓库

备注:

A  git status分别可以在②和③之前用,随时查看当前状态,②之前显示的是红色内容,③之前显示的绿色   Untracked是红色,git add后变成绿色色,git commit后变成普通颜色,

B  ②③步两步可用git commit -a -m "备注的内容" (或者git commit -am "备注的内容"  ) 一步给代替,效果如图2。

C  为什么会有②③这两个看似重复的步骤呢?直接改成一步不好吗?

暂存区 Index的作用:在commit前面的暂存区是可以随意的将各种文件的修改放进去的,这样我们就可以用多个指令精确的挑选出我们需要提交的所有修改,然后再一次性的(原子性的)提交到版本库。

原子性提交,每一个提交都是由多个文件的修改组成,而且这个提交是原子性的,要么这些修改全部成功,要么全部失败。
原子性提交带来的好处是显而易见的,这使得我们把项目整体还原到某个阶段或者时间点变得极为简便

D  出现了conflict怎么办?        (出现冲突会有两种情况------  一是:pull以后,远端和本地  二是:分支merge或者pop以后,本地的不同分支)

 合并冲突,最后重新走一遍上述步骤,add commit pull最后push(在合并冲突的过程会发现现在所处的位置 分支名/mergin)

 <<<<<<< HEAD

自己本地的内容
  =======

后加进来的内容
>>>>>> 

看看留哪个,把不用的和<<<<<<< =======>>>>>>>一起删去 ,注意把 <<<<<<< =======>>>>>>> 多出来的空行也删掉,否则下次还会冲突, git是按行来记录内容的,他不会智能的跳过空行

E  如果想pull或者push任意分支到任意分支怎么办?origin代表远端仓库   (这里需要搞清楚本地的所站在的分支和远端的分支两个概念)

    ①  git pull origin "分支名a"   ---    代表把  远端的分支名a  拉取到到当前所站在的分支上  括号里的就代表当前所站在的分支

     同理  git push origin "分支b"   ---  代表把当前所站在的分支内容推送到 远端分支b 

    ②  git pull origin "远端分支名c" : "本地分支名d"  ---    代表推送或者拉去指定分支到指定分支

   git push origin "本地分支名d" : "远端分支名c"

 注意:分支推送顺序的写法是<来源地>:<目的地>   所以: git pull是<远程分支>:<本地分支>,git push是<本地分支>:<远程分支>

    ③  当推送push到远端的时候,远端并没有你所写的分支会怎么办??远端会自动创建你写的分支名,并进行push操作。

F  git add -A进行了操作了哪些文件呢?  

被修改过或已删除文件和所有untracted的文件(新建的文件),与之相对应的是 git add -u,它修改过或已删除文件的信息添加到索引库。它不会处理untracted的文件(未跟踪的新文件)

G  git pull相当于git fetch+git merge,意思是:取回远程主机某个分支的更新,再与本地的指定分支合并(一下子进行了两步操作)

2、git remote命令(让你和远端仓库打交道)

Git要求每个远程主机都必须指定一个主机名。git remote命令就用于管理主机名。不带选项的时候,git remote命令列出所有远程主机

命令列表:

。$ git remote 命令列出所有远程主机。  ---  origin

$ git remote -v 参看远程主机的网址   --- https://github.com/yang123guo/git_test.git 

$ git remote add <主机名> <网址>     --  用于添加远程主机。

$ git remote rm <主机名>          --  用于删除远程主机。

$ git remote rename <原主机名> <新主机名>    --  用于远程主机的改名。

3、本地项目和远端仓库建立连接(本地仓库推送到远端仓库)

情况1:本地没有项目,从远端地址用git clone,这是会自动建立连接 

     在git clone的时候,所有本地分支默认与远程主机的同名分支,建立追踪关系,也就是说,本地的master分支自动"追踪"origin/master分支。

情况2:本地已经有项目

a、首先先init,得到隐藏的git文件夹(两种方法,一种是在目录下右键选择  Git init Here,另外一种是在node环境下输入 git init)

b、用git add -A 和git commit -m '' 先保存到本地git中

c、

第一句的意思是:添加一个远端的仓库,并申明地址url,其中git remote是操作远端的意思 add是添加的意思,origin代表远端的主机名(可以随便起,但第一个习惯用origin)最后的url是远端仓库地址

第二句的意思是:把本地仓库push到远程仓库(git push),并把origin设为默认主机和master为主分支   -u是在本地分支与远程分支之间,建立一种追踪关系(tracking)

         -u 等于 --set-upstream(建立追踪关系)

注意:在远端的github上的仓库里面不能内容(即使一个README.md文件也能让你push失败)

4、追踪关系是个什么东东??

在Git中‘追踪分支’是用与联系本地分支和远程分支的.

如果你在’追踪分支'(Tracking Branches)上执行推送(push)或拉取(pull)时, 它会自动推送(push)或拉取(pull)到关联的远程分支上.

git clone命令会自动在本地建立一个'master'分支,它是'origin/master'的‘追踪分支’. 而'origin/master'就是被克隆(clone)仓库的'master'分支.

你之前push过(git  push origin dev:dev),但是不代表已经建立了追踪关系,要正真的关系需要git push --set-upstream origin dev建立关系,

建立关系以后就可以用最简单的  (git push 主机名 分支名),当你只有唯一的主机和分支名(唯一追踪),用(git push)。

5、git push与git pull的补充

如果省略本地分支名,则表示删除指定的远程分支,因为这等同于推送一个空的本地分支到远程分支。

$ git push origin :master     等同于    $ git push origin --delete master       表示删除origin主机的master分支。

$ git push -u origin master     上面命令将本地的master分支推送到origin主机,同时指定origin为默认主机,后面就可以不加任何参数使用git push了。(以上提到过)

--force   (git push --force 强制推送)  尽量不用
 

6、git config  配置 命令

 获得和设置配置变量,这些变量可以控制Git的外观和操作的各个方面,他们会在三个地方被保存

  1./etc/gitconfig 文件:   包含了适用于系统所有用户和所有库的值。如果你传递参数选项’--system’ 给 git config,它将明确的读和写这个文件。  

  2.~/.gitconfig 文件 :     具体到你的用户。你可以通过传递--global 选项使Git 读或写这个特定的文件。

  3.位于git目录的config文件 (也就是 .git/config) :   无论你当前在用的库是什么,特定指向该单一的库。每个级别重写前一个级别的值。因此,在.git/config中的值覆盖了在/etc/gitconfig中的同一个值。

操作指令:

git config --list    ----   列出所有git里面的配置信息        其中git config  具体属性(如:git config user.name)   ---   会给出相应的信息

全局配置用户名和邮箱 ---  这个最常用,配置好以后就不用每次提交的时候输入了,这个地方配置我们的身份信息,作为自己参与团队协作的一个身份标记,比如谁对某个文件进行了修改。(用git config --list查看)

$ git config --global user.name 用户名      

$ git config --global user.email 邮箱

私人配置用 git config --local   (user.name 用户名  或者 user.email 邮箱)

其他配置

$ git config --global core.editor  xx编辑器   配置你的缺省文本编辑器

$ git config --global merge.tool xx diff工具  配置diff工具

别名修改(嫌长难记),(git config --global alias.别名 '指定名称')

比如把git status中的status变成st    $ git config --global alias.st status

7、git  log日志       按q键退出

git log    命令显示从最近到最远的提交日志。
git log  --pretty=oneline    如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline参数,一行显示,只显示哈希值和提交说明
 
还有许多许多参数。。。。。略
 
按一定的条件来筛选log
 
  1. 按数量
    1. -n:显示前n条log      git log -2  显示最近两条
  1. 按日期
    1. --after=
    1. 比如git log --after="2014-7-1”,显示2014年7月1号之后的commit(包含7月1号)
    2. 后边的日期还可以用相对时间表示,比如"1 week ago"和”yesterday",比如git log --after="yesterday"
    3. 这里的格式可以是什么?
    1. --before=
    1. 同上
    2. 另外这两条命令可以同时使用表示时间段,比如git log --after="2014-7-1" --before="2014-7-4"
    3. 另外--since --until和 --after --before是一个意思,都可以用
  1. 按作者
    1. --author=
    1. 比如git log --author=“John",显示John贡献的commit
    2. 注意:作者名不需要精确匹配,只需要包含就行了
    3. 而且:可以使用正则表达式,比如git log --author="John|Mary”,搜索Marry和John贡献的commit
    4. 而且:这个--author不仅包含名还包含email, 所以你可以用这个搜索email
  1. 按commit描述
    1. --grep=
    1. 比如:git log --grep="JRA-224"
    2. 而且:可以传入-i用来忽略大小写
    3. 注意:如果想同时使用--grep和--author,必须在附加一个--all-match参数
  1. 按文件
    1. - -(空格)或[没有]
    1. 有时你可能只对某个文件的修改感兴趣, 你只想查看跟某个文件相关的历史信息, 你只需要插入你感兴趣文件的路径[对,是路径,所以经常是不太好用]就可以了
    2. 比如:git log -- foo.py bar.py ,只返回和foo.py或bar.py相关的commit
    3. 这里的--是告诉Git后面的参数是文件路径而不是branch的名字. 如果后面的文件路径不会和某个branch产生混淆, 你可以省略- -,比如git log foo.py 
    4. 另外,后边的路径还支持正则,比如:git log  *install.md 是,指定项目路径下的所有以install.md结尾的文件的提交历史
    5. 另外,文件名应该放到参数的最后位置,通常在前面加上--并用空格隔开表示是文件
    6. 另外,git log file/ 查看file文件夹下所有文件的提交记录
  1. 按分支
    1. - -
    1. --branchName branchName为任意一个分支名字,查看某个分支上的提交记录
    2. 需要放到参数中的最后位置处
    3. 如果分支名与文件名相同,系统会提示错 误,可通过--选项来指定给定的参数是分支名还是文件名
    1. 比如:在当前分支中有一个名为v1的文件,同时还存在一个名为v1的分支
    2. git log v1 -- 此时的v1代表的是分支名字(--后边是空的)
    3. git log -- v1 此时的v1代表的是名为v1的文件
    4. git log v1 -- v1 代表v1分支下的v1文件
  1. 按内容
    1. -S"<string>"、-G"<string>"
    1. 有时你想搜索和新增或删除某行代码相关的commit. 可以使用这条命令
    2. 假设你想知道Hello, World!这句话是什么时候加入到项目里去的,可以用:git log -S"Hello,World!"
    3. 另外:如果你想使用正则表达式去匹配而不是字符串, 那么你可以使用-G代替-S.
    4. 这是一个非常有用的debug工具, 使用他你可以定位所有跟某行代码相关的commit. 甚至可以查看某行是什么时候被copy的, 什么时候移到另外一个文件中去的
    5. 注:-S后没有"=",与查询内容之间也没有空格符
  1. 按范围
    1. git log <since>..<until>
    1. 这个命令可以查看某个范围的commit
    2. 这个命令非常有用当你使用branch做为range参数的时候. 能很方便的显示2个branch之间的不同
    3. 比如:git log master..feature,master..feature这个range包含了在feature有而在master没有的所有commit,同样,如果是feature..master包含所有master有但是feature没有的commit
    4. 另外,如果是三个点,表示或的意思:git log master...test 查询master或test分支中的提交记录
  1. 过滤掉merge commit
    1. --no-merges
    1. 默认情况下git log会输出merge commit.  你可以通过--no-merges标记来过滤掉merge commit,git log --no-merges
    2. 另外,如果你只对merge commit感兴趣可以使用—merges,git log --merges
  1. 按标签tag
    1. git log v1.0
    1. 直接这样是查询标签之前的commit
    2. 加两个点git log v1.0.. 查询从v1.0以后的提交历史记录(不包含v1.0)
  1. 按commit
    1. git log commit :查询commit之前的记录,包含commit
    2. git log commit1 commit2:查询commit1与commit2之间的记录,包括commit1和commit2
    3. git log commit1..commit2:同上,但是不包括commit1
    1. 其中,commit可以是提交哈希值的简写模式,也可以使用HEAD代替
    1. HEAD代表最后一次提交,HEAD^为最后一个提交的父提交,等同于HEAD~1
    2. HEAD~2代表倒数第二次提交

8、版本切换和回退、删除 

   删除:工作区的文件       rm(linux命令)或者 右键  

   工作区的回退:1、只修改了工作区的内容,还没有add,忘记修改内容并且ctrl+s保存了很多次代码,或者是误删除了东西    采取的回退方式是:暂存区内容覆盖当前工作区的内容  git checkout  -- xxxx

                     2、修改并且已经add,但还没有commit ,这时候记录在index暂存区有了记录,此时checkout文件是没用了,得本地仓库回退覆盖(git reset)让当前文件回到上一次提交时的状态

              此时先 git reset HEAD XX文件 (理解为:暂存区的修改撤销掉) 此时再调用: git checkout -- XX文件 (空暂存区覆盖工作区)  工作区的文件即可恢复原样!

     版本回退:    版本:用commit提交到本地仓库所生成的一个快照,用HEAD表示当前版本,用git log打印出来的版本ID是十六进制的哈希算法值,如:ea34578d5496d7dd233c827ed32a8cd576c5ee85

          上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100

          所以表示版本信息有三种方法   1、 HEAD^n   2、HAED@{n}(1,2按版本保存顺序找,弊端:只能回退不能前进,回退以后比他还晚的就消失了)   3、版本ID  十六进制的哈希算法值 , 如:ea34578d5496d7dd233c827ed32a8cd576c5ee85 

          回退版本的指令是: git reset --hard 版本   (如:回到上一个版本 git reset --hard HEAD^ )    回到任意一个版本  (git reset --hard 3628164/版本ID输入几位就可以了)

         这里的版本回退主要是针对本地仓库来说的,本地的工作区和暂存区是同时会跟着的。

   重返未来(找回回退):git reflog  找回并列出所有版本序列(包括已经删除的,不过有几个月的时间限制,太久了也不行)   git reset --hard  版本  回到未来版本,此时你可以看见列表区域的HAED是重新计算过的,

          

         如图

          其中的    暂存---->工作区   的checkout意思是:checkout可以让暂存东西覆盖工作区,而不是add命令以后 修改内容进入了暂存区再使用checkout,这时候checkout已经无效了。(他的原理是 从 ..  到 ..  的指针指向导致的覆盖

          同理的还有git reset命令,也是从前到后的覆盖,按图中的意思是:版本回退的机理是仓库覆盖了index暂存。     ---- 对的,但是注意的是git reset HEAD XX文件最后是文件名而不是版本号

          问题:那么版本回退reset的时候只是本地覆盖暂存吗?本地仓库变了没?可不可以直接push??     结论:可以直接push,push以后是变更后了本地仓库内容,此时本地工作区也跟着变了。说明reset可以在本地仓库多个历史版本中切换。

结论:git reset 有两种回退方法:图中给出了本地仓库到暂存区的回退 git reset HEAD XX文件 (HEAD 未加版本号代表当前最新版本) 

   本地仓库之间也可以相互回退跨越 git reset --hard  HEAD 版本  (此时相关的工作区也是跟着变化了)     对比    git reset  HEAD 版本(工作区不跟着变化)

      git checkout -- 文件名  命令中的--很重要,没有--,就变成了“切换到另一个分支”的命令

9、其他  

Git命令的自动补全    ------      输入git命令后   按Tab就可以了

原文地址:https://www.cnblogs.com/faith3/p/6103218.html