[Git] 1 - Basic

Posted by Dongbo on November 18, 2019

摘自『Pro Git』以及 Git手册
仅用于本人理解和查阅。不全之处,日后补充。

Git分支

Git每次提交可以简单理解为创建一个当前提交文件的快照,并且当前的提交对象包含一个指向上次提交对象的指针。但是单纯创建分支并没有产生提交。当你从新分支的新版本回滚时,是将新的提交对象替换为了旧版本的提交对象。

Git分支实质上是包含所指对象校验和(长度为40的SHA-1值字符串)的文件

Q:提交记录多了之后,每个版本的快照会不会占用很多空间?
A:如果是没修改过的文件,新提交里的快照似乎也只是用一个指针指向原本的文件罢了;如果每个版本都对许多文件进行了大量的修改,那占用空间增多是无法避免的。

Q:那么每个版本的文件快照(提交对象)是什么东西?

忽略文件

可在git仓库目录中的.gitignore文件中,设置忽略的文件,如

1
2
*.[oa]
*~

将会忽略所有以.o.a以及~结尾的文件。

格式规范如下:

  • 忽略所有空行和以#开头的行
  • 可以使用标准的glob模式(简化的正则表达式)匹配
  • 模式匹配可以以/开头防止递归
  • 可以以/结尾指定目录
  • 可以在模式前加!取反

*匹配0个或任意个字符;
[abc]匹配方括号中的一个字符;
[0-9]使用短划线分割两个字符则匹配两个字符范围内的任意字符(一个);
使用两个星号**匹配任意中间目录, 如a//**/z可以匹配a/z, a/b/za/b/c/z

1
2
3
4
5
6
7
8
    # ignore all files in the build/ directory
    build/

    # ignore doc/notes.txt, but not doc/server/arch.txt
    doc/*.txt

    # ignore all .pdf files in the doc/ directory
    doc/**/*.pdf

Git HEAD指针

HEAD^ ==> HEAD的父指针
HEAD~2 ==> HEAD的祖父指针,相当于HEAD^^
HEAD^2 ==> HEAD的第二父提交,只在合并分支的提交中可以使用(因为有不止一个父提交,第一父提交是合并时所在的分支,第二父提交是合并进来的分支)

Command

  • git diff

    显示尚未暂存的改动与暂存区文件快照之间的差别

  • git rm

    1
    2
    3
    
      # 不加参数时,从暂存区和工作区移除文件。匹配多个文件使用 * 号时,需要加反斜杠\
    
      --cached    # 仅从暂存区移除,在工作区保留
    
  • git mv

    文件改名

    1
    
      git mv oldName.md newName.md
    
  • git log

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
      -p      # 显示每次提交的内容差异
      -2      # 显示最近两条提交记录
      --since=2.weeks  
      --since="2019-10-01"
      -S      # 显示添加或者移除了某些特殊字符串的提交
      -Sfunction_name     # 查找添加/移除了"function_name"的提交
      --pretty # =oneline # =format:"%h "
      --oneline
    
      *--*----*---*---master
          \
           ----*---*---exp
    
      master..exp     # 查看在exp分支而不在master分支中的提交
        
      # 在分支引用前加^或--not指明不希望包含在内的分支,因此上式等价于
      exp ^master # 或 exp --not master
    
      --left-right master...exp       
      # 被master和exp其中一个包含但不是二者共有的提交
      # --left-right将标识该提交属于左/右(master/exp)
    
  • git checkout

    1
    2
    3
    4
    5
    6
    
      git checkout -- <filename> 
      # 用某次提交的文件来覆盖暂存区和工作区的文件,所以会丢失工作区中的修改
      # 请慎重使用
    
      -b <branch name>
      # 创建并将HEAD移动到一个新分支
    
  • git commit

    1
    2
    3
    
      --amend   
      # 将修改合并到上一次commit中,类似做了rebase操作,会修改SHA-1的校验和
      #(所以如果push到远端了就不要使用。why?远程仓库不能一起修改吗)
    
  • git remote

    1
    2
    3
    
      https  
      git://  
      git@github  
    
  • git fetch

    从远程仓库拉取数据,但是不合并。若希望拉取数据同时合并请使用pull

    p80: 抓取到新的远程跟踪分支时,本地不会自动生成一份可编辑的副本,只有一个不可修改的指针

    Q:到底抓取了什么东西下来?

  • git stash

    暂存未完成并且不想提交的改动

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
      git stash / git stash save      # 暂存
    
      git stash list    
      # 查看栈中的暂存
    
      git stash apply ( stash@{2} )  
      # 不指定则默认为0
    
      git stash pop   
      # 应用暂存,然后丢弃
    
      git stash drop ( stash@{2} )    
      # 丢弃指定的暂存
    
  • git reset

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
      --soft
      # 只移动HEAD指针
    
      --mixed     
      # 移动HEAD指针,并且回滚暂存区。因此会回到那次提交之前的状态(如果之后你对工作区有改动的话)
    
      --hard
      --merge     
      # 移动HEAD指针,并且改变暂存区和工作区
      # 目前需要的回滚通常要改变工作区,所以这两个选项会用的比较多
    
  • git checkout

    1
    2
    3
    4
    5
    
      git checkout [branch]
      # 类似git reset --hard [branch],并且不会移动分支的指针
    
      git checkout [branch] filename
      # 类似git reset --hard,不移动HEAD指针,修改暂存区,不同的是会覆盖工作区中的文件
    

    回想一下,git reset --mixed移动HEAD指针, 但是同样我们也可以用--soft把HEAD移动到想要的位置.

  • git push

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
      -f
      --force
      # 
    
      --force-with-lease
      --force-with-lease=<refname>
      --force-with-lease=<refname>:<expect>
      # 如果远程仓库里的记录不是当前要推送提交的上游分支(比如使用了rebase)
      # git push默认拒绝这样的操作。此时需要--force-with-lease选项。
    
  • git pull

跟踪分支

从一个远程分支checkout一个本地分支会在本地创建“跟踪分支”,它跟踪的分支叫做“上游分支” 在跟踪分支上运行git pull能够自动抓取上游分支并且合并到当前的跟踪分支。

可以使用

1
2
3
4
5
6
7
8
git checkout --track origin/serverfix   
# 将serverfix设为跟踪分支

git checkout -b sf origin/serverfix     
# 将sf设为跟踪分支

git branch -u/--set-upstream-to origin/master
# 将当前分支的上游分支修改为origin仓库的master分支

(TODO)merge, rebase


  • –depth=1 ->断点续传?

    1
    2
    
      # e.g. 
      git clone --depth=1 --single-branch --branch fuck-branch url