me
me copied to clipboard
课程笔记: 玩转 Git 三剑客 (苏玲)
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 --list
或git 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 log
和git 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?
- 开启rebase过程,
git rebase -i commitid
, 这里填写目标commit的parent commitid - 在rebase交互过程中将目标commit从pick改为reword
- 在reword中修改message
怎样把连续的多个commit整理为1个commit?
- 比如现在有commit c1-c6, 现在需要将c2-c4合并,则
git rebase -i c1
- 将c3,c4从pick改为squash,即将c3,c4的内容meld给c2
怎样把间隔的多个commit整理为1个commit?
- 比如现在有 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支持哪些同步协议?
- Local Protocol:
git clone /srv/git/project.git
或git 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