git

animation
book

  • 代理

    1
    2
    3
    4
    5
    #只对github.com
    git config --global http.https://github.com.proxy socks5://127.0.0.1:7890

    #取消代理
    git config --global --unset http.https://github.com.proxy
  • 使用 token:https://<access token>@github.com/<userName>/<repository>.git

  • git in git,也就是 submoudle 会发生奇妙的事件

  • git

  • 其他版本控制系统大多是 delta-based,但 git 是给每个文件保存一个快照,然后有一个索引指向(如果没有修改,就用以前的索引)

  • git config --global init.defaultBranch main

  • .gitnore

    • Blank lines or lines starting with # are ignored.

    • Standard glob patterns work, and will be applied recursively throughout the entire working tree.

    • You can start patterns with a forward slash (/) to avoid recursivity.

    • You can end patterns with a forward slash (/) to specify a directory.

    • You can negate a pattern by starting it with an exclamation point (!).

  • git commit -a 自动 add tracked file 并且提交

  • git rm 也会将文件从工作区内删除,git rm --cached 保留工作区

  • 重命名,最好用 git rm

  • 普通的 git reset a 只是取消 staged,但并不会对工作区文件修改

  • 突然发现我之前解决的误区还在困扰着我,文件夹的实际大小并不包含文件,也就是说文件加其实包含的内容很少

  • learn git inner

  • 除了文件目录的概念,有三个关键概念(存储在 objects 中)

    blob:只是存储着文件实质二进制内容
    tree:每次 commit,都会产生一个 tree,它的内容实际上就是所有该次提交需要指向的新的 blob 的 hash 值(以及对应的文件名,权限)
    commit:tree 的 hash 值,parent tree 的 hash 值,author 相关信息,commitor 相关信息,message。

    此外还需要了解的是:
    index:也就是存储着 staged 的 blob 的 hash 值(以及对应的文件名,权限)。即是由它组成了 tree 的一部分

  • git 文件目录:

    objects 存储着 blob,info(pack 的索引) 和 pack 存储着压缩的二进制信息。有取的是,其他文件夹是 hash 值得头两个字符,也是一个索引方式,里面存储着实际的 blob(content 信息,没有 meta data)。这么做的原因是如果说是有很多 blob 存储在一个文件夹中,那么去寻找是很慢的事情,所以通过进一步索引可以加快速度

    refs/heads 存储着分支信息,实际上每个分支名都有一个文件,文件的内容只是一个 commit 的 hash 值。

    index 存储着 staged 的 blob 的 hash 值(以及对应的文件名,权限)。即是由它的内容组成了 tree 的一部分。此外一个文件在 git 中的诞生,也是从加入 index 中开始(因为在此创建了 blob)

    HEAD 分支名(以 ref 起头来标志)或者是 commit hash 值。

  • git status 实质就是比较 working direcotry 和 index 和 HEAD 指向的 commit

  • git merge 几种方式

  • git branch -f <branch_name> <commit_name> 强制改变分支指向

git 服务器

  • 本地协议:克隆本地仓库:git clone /srv/git/project.git,在共享文件系统有用。http 协议,ssh 协议,git 协议..
  • 简单搭建 server
  • 复杂搭建可以用 gitlab

命令

1. basics

  • ssh -T git@github.com //-T 就是不分配伪终端,只显示连接信息
    测试能否连接到 github
    确定已经有添加 ssh 密钥,确定 config 文件配置正确,确定能 ping 通 github.com
  • git init
  • git add (.)
  • git commit -m ‘’
  • git status
  • git rm
  • git cherry-pick <commit> (复制一个特定的提交到当前分支)
  • git blame filename 显示谁修改了文件

2. diff

  • git diff 工作区与暂存区
    – <filename> 指定文件(注意空格)
  • git diff HEAD 工作区与 commit
  • git diff –chached(暂存区与commit)

即未使用参数,默认是工作区与 xx 比较

3. reset

  • git reset <file> (将某文件从暂存区移除,不修改工作区,不加文件是所有)
  • git reset –hard (移除暂存区修改,删除工作区修改)
  • git reset <commit> (可以用 head^ 回滚到指定版本,清除暂存区,但保持工作区不变)
  • git reset –hard <commit> (回滚到指定版本,清除暂存区,删除工作区修改)
    git reflog 可以查看被删除的版本号

–mixed 是默认参数,保留工作区,修改暂存区,不会移动 head 指针
–hard 修改工作区和暂存区,会移动 head 指针,此时提交会丢失指定版本之后的内容

4. branch

  • git branch 显示分支
  • git branch <branchname> 创建分支
    -d 删除
    -m 改名
    -f 后跟两个分支,让前者强制指向一个提交(如果同游,那么用 rebase 也可以)
    -u <name1> (<name2>) 让 当前分支(name2) 跟踪 name1
  • git checkout <branchname> 切换分支
    -b <name1> (<name2>) 新建并切换到 name1,设立对远程分支 name2 的跟踪
  • git merge <branchname> 采用 Fast Forward 合并分支(此模式不会显示合并信息)
    –no-ff 不使用 Fast Forward 模式,会显示合并信息,会产生新的 commit 所以同时需要 -m 参数
  • git switch 作用同 checkout
  • git cherry pick <commit> 复制一个特定的提交到当前的分支(指复制相同的改动操作)
  • git rebase <commit>
    变基,合并两个分支成一条线(直到公共祖先)
    以当前位置为最新的提交(即当前位置动)
    或者指定两个提交,以第一个提交为最新的提交(即前者不动,后者动)
    会自动将 head 指向最后一个参数
  • git branch –set-upstream-to <branch-name> origin/<branch-name> 关联上游分支,不用记,会有提示

5. remote

  • git remote -v 查看远端仓库信息
  • git remote add <name> <url>(eg:git@github.com:llleixx/helloworld.git)
  • git remote rm <name> 删除远程仓库的绑定
  • git pull
  • git push <remotename> <commit>(:<branchname>) 将某个提交推送到远端某个分支
    -u 关联远程分支
    -f 强制
    git push origin :foo 传递空的本地分支可以用于删除远程的分支
  • git fetch
    <remotename> <commit>(:<branchname>) 将远程的某个提交下载到本地并且将一个分支指向它(这里的分支是本地的,而且如果不存在会自动创建,普通的 fetch 只是远程的指向,因为还没有 merge)
  • git push origin --delete branchname 删除远端分支
  • git clone <name> (eg:git@github.com:llleixx/helloworld.git)

6. log

  • git log -<limit>
    -p 详细信息
  • git log – <file>
  • git log –graph
  • git relog (命令历史)

7. stash

  • git stash 储存工作区和暂存区(切换分支会丢失工作区和暂存区信息)
    sava “message” 同时储存注释信息
  • git stash list 查看
  • git stash apply (<stashname>) 恢复但不删除stash,默认最新
  • git stash drop (<stashname>) 删除stash
  • git stash pop (<stashname>) 恢复并删除

8. tag

  • git tag 查看所有标签
  • git tag <tagname> 给 HEAD 指向打 tag
    -d 删除标签
  • git tag <tagname> <commit>
  • git tag -a <tagname> -m <annotation> <commit> 创有说明的标签
  • git show <tagname> 显示说明
  • git push origin <tagname> 推送某个标签
    –tags 是推送所有标签

9. config

  • git config –global –list
  • git config –global user.name xx
  • git config –global user.email “email@email.com

  1. HEAD表示当前分支最新提交版本,HEAD^上个版本,HEAD^^上上个版本,上100个版本可以写HEAD~100

  2. git status 查看状态

    1
    2
    3
    Untracked files 未跟踪(新创建,从未add过的文件)
    Changes not staged for commit 未add
    Changes to be committed add但未commit
  3. 分支间相同文件进行不同修改会有冲突,此时merge失败
    此时可以用 git status 告诉我们冲突文件
    查看文件内容,Git用<<<<<<<=======>>>>>>>标记出不同分支的内容
    修改(修改成你想要的样子,可以与所有分支都不同),add,commit。就能成功合并了(不用再merge,相当于merge失败→修改→add,commit→合并成功)

  4. origin/dev 像调用本地分支一样调用远程分支(其实两者没什么差别)

  5. 使用 https 协议,可以通过设置 credential helper 来只用第一次输入密码
    git config –global credential.helper store //这是全局配置,执行后,会在用户目录下(这里没有指定位置)生成 .git_credential 里面存储着账号和密码

  6. 使用 ssh(git) 协议更快,设置密钥后才能使用

  7. git merge 和 git rebase

    git merge master feature 将 master 合并到 feature 上

    git merge 每次合并上游更改时 feature 分支都会引入一个外来的合并提交。如果 master 非常活跃的话,这或多或少会污染你的分支历史。

    git rebase 它会把整个 feature 分支移动到 master 分支的后面,有效地把所有 master 分支上新的提交并入过来。但是,rebase 为原分支上每一个提交创建一个新的提交,重写了项目历史,并且不会带来合并提交。

    不过,这种简单的提交历史会带来两个后果:安全性和可跟踪性。如果你违反了 rebase 黄金法则,重写项目历史可能会给你的协作工作流带来灾难性的影响。此外,rebase 不会有合并提交中附带的信息——你看不到 feature 分支中并入了上游的哪些更改。

    综上,rebase 适用于开发 feature 分支时,master 分支已经被更新,需要再在新的 master 分支下开发,这时就可以用 rebase 将当前分支移动到 新的master 分支后

代码回滚

  1. 工作区:
    git checkout -- a.txt
    git checkout -- . 所有
    git checkout <commitID>(head) <filename>

  2. 暂存区:
    git reset HEAD .
    git reset HEAD a.txt
    不加参数是采用了默认的 –mixed 参数

    只改变暂存区,所以如果想再还原工作区,需要用到1

  3. 本地分支
    git log 得到提交id
    git reset –hard HEAD^ 回到最新的一次提交
    git reset –hard 回到你想要的版本
    git reset HEAD^ 此时代码保留,回到 git add 之前

  4. 远程仓库
    git log
    git reset –hard
    git push -f origin HEAD(或者当前分支名) 强制提交
    or
    git revert HEAD
    git push origin master(不用 -f 了)

  5. git revert 和 git reset 区别

    git revert 是指定一个提交,在当前分支的基础上新建一个提交(为指定提交的副本),常用于远程
    git reset 是回到某次提交,提交及之前的commit都会被保留,但是此commit id之后的修改都会被删除

    这两个命令都需要 HEAD 指向一个分支(不是直接指向提交,不然不知道操纵的哪个分支)

  6. git commit –amend -m ‘sdfa’

    相当于删除上次提交,换成当前这次

  • 一般情况是 head 指向分支,分支指向一个具体提交,我们可以用 git checkout <commit name> 来分离 head 和分支

  • ^ 上一个,~<num> 前多个。main^^,即 ^ 可以用于任意一个表示的合法分支(不能是提交 hash 值)

    ^2 也可以有数字,这是用于一个结点有多个父亲时,用 ^2 代表第二个父亲

  • git cherry-pick <commit name> 可以同时指定多个提交(这些提交甚至可以不是祖先关系,但可能有冲突),来将对应的提交创建一个副本到当前分支上(rebase 是指定一个提交,然后合并到公共祖先的整个路径,而且原来的会删除)

  • 交互式的 rebase:

    git rebase -i HEAD~4 指定一个提交,可以调整当前提交到指定提交内的提交(不包括指定的提交),所以两者需要是祖先关系?

    作用:

    1. 调整提交记录的顺序
    2. 删除不想要的提交
    3. 合并提交
  • git commit --amend 修改最新的提交(不会产生新的提交)

  • git describe (<commit>) 描述指定提交(或当前)的上游最近的 tag

    返回的组成是 <tag>_<numCommits>_g<hash>,tag 名称,距离,和询问的提交 hash 值

远程

  • 远程默认名称为 origin

  • 默认不能动远程分支,切换到分支名自动会变成 HEAD 分离状态

    也就是说 git checkout origin/main 会指向对应的提交,而不是 main

  • git fetch 从远程仓库下载本地仓库缺失的提交记录,更新远程分支指针。即同步远程仓库(他并不会改变你本地的仓库,这两者不同)。

  • git pull 先抓取(fetch),后合并(merge)本地仓库(会在本子仓库产生一个新的提交),即是(git fetch, git merge)的缩写,注意合并是与当前指向的提交合并。

  • git push git push 前需要保证先与远程是同步的,才能 push 成功

  • git pull --rebase 就是 fetch, rebase 的缩写,也就是为了提交先满足同步远端时,可以用这个命令先同步

  • 从最最后的最上游开始 rebase 才能保证不丢失分支(分支在一条线上),因为 rebase 是建立副本,删除原来,分支信息不会跟着移动


git
https://lllei.top/2023/10/24/git/
作者
Lei
发布于
2023年10月24日
许可协议