me icon indicating copy to clipboard operation
me copied to clipboard

课程笔记: 玩转 Git 三剑客 (苏玲)

Open nonocast opened this issue 2 years ago • 0 comments

version: git 2.37.0

三剑客

  • git
  • GitHub
  • GitLab

git

git 怎么配置?

通过git config命令实现,配置分为local, global, system 3个级别, 通过--list查看对应的配置:

~ git config --list (当前上下文下的合并配置, 即system+global+local, 局部优先)
~ git config --list --local (仅针对当前仓库)
~ git config --list --global (对当前用户下所有仓库有效)
~ git config --list --system (对所有用户有效)
  • system: linux在/etc, macOS通过brew安装后则在/opt/homebrew/etc
  • global: 对应到~/.gitconfig
  • local: 对应到仓库目录.git/config
  • 随时通过git config --listgit config -l查看当前配置

为什么要配置user.name和user.email?

一般安装后都需要配置global user, 如下:

~ git config --global user.name 'your_name'
~ git config --global user.email '[email protected]'

主要是因为git commit时需要填写name/email标识提交人,如果没有配置,git会根据当前系统的username和hostname自动生成,这显然不是我们希望的:

git101 git:(main) ✗ git commit -m "whatever"
[main cc0ff5d] whatever
 Committer: nonocast <[email protected]>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"
    git config --global user.email [email protected]

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

 1 file changed, 1 insertion(+)
  • 你可以通过不同的身份进行commit,通过git log可以查看提交者信息。
  • 通常情况下,你会在不同的环境下采用不同的身份进行提交,比如公司项目就需要采用公司邮箱,否则代码统计不到你,而社区则会采用社会化身份,所以要仔细设定不同项目的提交身份。

git 本地仓库怎么提交?

git本地仓库分为3个区域:

  • 工作区 (working directory)
  • 暂存区 (staging area)
  • 仓库区 (repository .git)

一般情况下,通过git add将工作区内容加入到暂存区,然后通过git commit将暂存区提交仓库区。

如何放弃暂存区的所有修改?

比如git add修改文件,或者做了mv操作等等,只要我没有commit,那么就可以直接通过git reset --hard撤回到原先状态。

怎么查看git log?

  • git log: 所有commit的完整信息 (默认当前分支)
  • git log -n4: 最近2次commit的完整信息
  • git log --oneline: 所有commit仅message
  • git log -n4 --oneline: 最近4次commit的message
  • git log --all (所有分支)
  • git log --all --graph
  • git log --all --graph --oneline
  • git log --online --all -n4 --graph: 查看所有分支上最近4个commit

可以通过git help loggit help --web log查看进一步的帮助。

怎么创建切换branch?

  • 创建分支: git branch branch-name
  • 切换分支: git checkout branch-name
  • 创建同时切换分支: git checkout -b new-branch-name
  • 查看分支: git branch

什么tig?

tig - text-mode interface for Git

tig        [options] [revisions] [--] [paths]
tig log    [options] [revisions] [--] [paths]
tig show   [options] [revisions] [--] [paths]
tig reflog [options] [revisions]
tig blame  [options] [rev] [--] path
tig grep   [options] [pattern]
tig refs   [options]
tig stash  [options]
tig status
tig <      [Git command output]

如何修改过往commit的meessage?

16 | 怎么修改老旧commit的message?

  • 开启rebase过程, git rebase -i commitid, 这里填写目标commit的parent commitid
  • 在rebase交互过程中将目标commit从pick改为reword
  • 在reword中修改message

怎样把连续的多个commit整理为1个commit?

17 | 怎样把连续的多个commit整理成1个?

  • 比如现在有commit c1-c6, 现在需要将c2-c4合并,则git rebase -i c1
  • 将c3,c4从pick改为squash,即将c3,c4的内容meld给c2

怎样把间隔的多个commit整理为1个commit?

18 | 怎样把间隔的几个commit整理成1个?

  • 比如现在有 commit c1-c5, 现在需要将c3和c5合并,则git rebase -i c2
  • 将commit顺序c2,c3,c4,c5改为c2,c3, c5, c4, 同时将c5改为squash

怎么比较暂存区和HEAD的差异?

  • git diff --cached

怎么比较工作区和暂存区的差异?

  • 查看所有差异: git diff
  • 查看特定文件的差异: git diff -- readme.md index.html

如何让暂存区恢复成和HEAD的一样?

  • 恢复暂存区,不改变工作区: git reset HEAD
  • 恢复暂存区的同时,也将工作区恢复为HEAD: git reset --hard HEAD

如何让工作区的文件恢复为和暂存区一样?

  • git checkout -- readme

reset and checkout

  • 改变暂存区: git reset
  • 改变工作区: git checkout

取消最近的几次提交?

比如有c1,c2,c3, 现在HEAD指向c3,然后通过git reset --hard c1,此时工作区恢复为c1, 暂存区清空, HEAD指向c1。

git支持哪些同步协议?

Git - The Protocols

  • Local Protocol: git clone /srv/git/project.gitgit clone --bare /srv/git/project/.git
  • The HTTP Protocol: smart HTTP and Dumb HTTP, 优先采用smart HTTP
  • The SSH Protocol: git clone ssh://[user@]server/project.git
  • The Git Protocol: git clone git://server/project.git

注:

  • project.git指bare repository,即没有working directory
  • smart有传输进度,dumb没有

git是如何考虑多个仓库的同步的?

一个git仓库可以通过git remote管理和外部仓库的连接, 如下:

# hello
~ git init hello && cd hello
Initialized empty Git repository in /.../hello/.git/
~ echo "hi,hello" > hello.md 
~ git add hello.md 
~ git commit -m "initial hello.md"
[main (root-commit) e2d4af5] initial hello.md
 1 file changed, 1 insertion(+)
 create mode 100644 hello.md

# foo
~ git init foo && cd foo
Initialized empty Git repository in /.../foo/.git/
~ echo "hi,foo" > foo.md 
~ git add foo.md 
~ git commit -m "initial foo.md"
[main (root-commit) 324e318] initial foo.md
 1 file changed, 1 insertion(+)
 create mode 100644 foo.md

# 同样的方式建立bar repo

此时目录下有hello, foo, bar三个仓库,各自有一个md,然后通过git remote 建立连接:

~ git remote add foo ../foo
~ git remote add bar ../bar
~ git remote 
bar
foo
~ git remote -v
bar	../bar (fetch)
bar	../bar (push)
foo	../foo (fetch)
foo	../foo (push)

通过git fetch就可以将远端的内容复制到本地仓库:

~ git fetch foo
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 187 bytes | 187.00 KiB/s, done.
From ../foo
 * [new branch]      main       -> foo/main
~ git fetch bar
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 191 bytes | 191.00 KiB/s, done.
From ../bar
 * [new branch]      main       -> bar/main
~ git branch -av
* main             56e8d74 initial hello
  remotes/bar/main 775d204 initial bar
  remotes/foo/main 986eac5 initial foo
  • 底层的逻辑依然是非常清晰的,就是每个仓库管好自己的branch, commit,然后如果添加remote,则将远端的仓库全部拉到本地形成副本,副本以remote name作为prefix,即foo/main, bar/main,互不干扰。

  • 在这个逻辑之上,我们来考虑如何关联hello/main和foo/main两个分支的关联。

  • git fetch foo, Download objects and refs from another repository, 即包括tree, commit, branch, tag, blob等等

  • git fetch foo main, 只取和main有关的objects和refs,对应的分支命名为: foo/main

  • 命令格式: git fetch <远程主机名> <分支名>, 以git fetch origin main为例,即获取origin远端仓库的main分支下所有相关内容

  • 基于git branch <new_branch> [from_branch], 可以git branch foo foo/main, 或者git checkout -b foo foo/main

  • 当然你可以直接将fetch回来的foo/main和本地仓库的main合并(merge),即直接得到了别人的代码,git merge foo/main, 实践中需要git merge foo/main --allow-unrelated-histories

  • git pull <远程主机名> <远程分支名>:<本地分支名>, 本质上就是pull然后merge

  • 此时就应该在本地仓库main分支下git pull foo main

  • 借助git branch --set-upstream main origin/main建立追踪关系后,就可以省略为git pull foo

  • 又因为当前分支只有一个upstream时可以省略remote,所以就简化成最终的git pull,其实本意是git pull foo main,再展开就是git fetch, 然后git merge

参考教程

nonocast avatar Jul 01 '22 03:07 nonocast