「学习笔记」Git 基础

2. Git 基础

git status

  • git status:查看当前状态
    • git status -s:简化输出
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

new file: README
modified: CONTRIBUTING.md

$ git status -s
M README
MM Rakefile
A lib/git.rb
M lib/simplegit.rb
?? LICENSE.txt

.gitignore

可以使用 glob 模式匹配。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 忽略所有前缀长度 >= 2 的 .a 文件,例如忽略 foo.a 但不忽略 p.a
??*.a

# 但跟踪所有的 lib.a,即便你在前面忽略了 .a 文件
!lib.a

# 只忽略当前目录下的 TODO 文件,而不忽略 subdir/TODO
/TODO

# 忽略任何目录下名为 build 的文件夹
build/

# 忽略 doc/notes.txt,但不忽略 doc/server/arch.txt
doc/*.txt

# 忽略 doc/ 目录及其所有子目录下的 .pdf 文件
doc/**/*.pdf

git diff

  • git diff:比较工作和暂存
  • git diff --staged:比较暂存和最新提交

git commit

  • git commit -a:自动将已跟踪文件 update
    • 不等于 git add -A

git rm

  • git rm <file>:也会移除工作区文件
    • --cached 避免
  • git mv <old_file> <new_file>

git log

  • -p -2:显示最近两次提交的差异
  • --pretty=online:单行显示
  • --graph:显示分支的树形图

2.4 撤销操作

  • git commit --amend:修补最后一次提交
  • git reset HEAD <file>:撤销文件的暂存
  • git checkout -- <file>:撤销文件的修改(危险

2.5 远程仓库的使用

  • git remote -v:查看远程仓库名称和 url
  • git remote add <shortname> <url>:添加远程仓库
  • git remote show <remote>:查看远程仓库的更多信息
    • rename/remove
  • git fetch <remote>:从远程仓库拉取数据
  • git push <remote> <branch>:推送数据到远程仓库

2.6 打标签

查询:

  • git tag:列出标签
    • -l "v1.8.5*":列出所有符合模式的标签
  • git show <tagname>:查看标签信息

创建:

  • git tag -a <tagname> -m "my version 1.4":创建附注标签
  • git tag <tagname>:创建轻量标签
  • git tag -a <tagname> 9fceb02:补办标签

删除:

  • git tag -d <tagname>:删除标签

标签不会在 git push 时自动推送,必须手动推送标签:

  • 添加:git push origin <tagname>git push origin --tags
  • 删除:git push origin --delete <tagname>

2.7 Git 别名

  • git config --global alias.unstage 'reset HEAD --'
    • git unstage <file>:等价于 git reset HEAD -- <file>
  • git config --global alias.visual '!echo hello'
    • git visual:等价于 echo hello

3. Git 分支

3.1 分支简介

Git 储存三种对象:

  • commit:储存 commit 信息,指向对应快照的 tree 根节点
  • tree:储存路径树结构
  • blob:储存文件

HEAD 指向当前所在分支。

  • 创建:git branch <newbranch>
  • 删除:git branch -d <branch>
  • 切换:git checkout <branch>

也可以用 git checkout -b <newbranch> 直接创建并切换。

3.2 分支的新建与合并

  • git merge <branch>HEAD = merge(HEAD, branch)
    • --no-ff:禁用快进合并

快进:若 HEADbranch 的祖先,则可以直接跳到 branch,称为快进。

如果出现冲突,需要手动去对应文件里修改,再用 git addgit commit

1
2
3
4
5
6
7
<<<<<< HEAD:index.html
<div id="footer">contact : email.support@github.com</div>
======
<div id="footer">
please contact us at support@github.com
</div>
>>>>>> iss53:index.html

3.6 变基

1
2
3
4
5
git checkout experiment
git rebase master

git checkout master
git merge experiment

变基:提取当前分支(experiment)中到最近公共祖先引入的修改,然后在目标分支(master)上重新应用,并修改当前分支的提交。(即 HEAD' = branch + (HEAD - LCA)

整合结果相同,但历史更加简洁。

进阶:

  • git rebase --onto master server client,将 client 减去 server 的修改应用到 master 上。
  • git rebase master server,将 server 的修改应用到 master 上。

变基前:

变基后:

风险:如果提交存在于你的仓库之外,而别人可能基于这些提交进行开发,那么不要执行变基。——也就是说,只在本地分支上使用变基。

Figure 47. 你将相同的内容又合并了一次,生成了一个新的提交

Figure 47. 你将相同的内容又合并了一次,生成了一个新的提交

高级魔法:用 git rebase teamone/master 可以实现智能变基合并(丢弃 C4 和 C6)。

合并和变基的区别:

至此,你已在实战中学习了变基和合并的用法,你一定会想问,到底哪种方式更好。 在回答这个问题之前,让我们退后一步,想讨论一下提交历史到底意味着什么。

有一种观点认为,仓库的提交历史即是 记录实际发生过什么。 它是针对历史的文档,本身就有价值,不能乱改。 从这个角度看来,改变提交历史是一种亵渎,你使用 谎言 掩盖了实际发生过的事情。 如果由合并产生的提交历史是一团糟怎么办? 既然事实就是如此,那么这些痕迹就应该被保留下来,让后人能够查阅。

另一种观点则正好相反,他们认为提交历史是 项目过程中发生的事。 没人会出版一本书的第一版草稿,软件维护手册也是需要反复修订才能方便使用。 持这一观点的人会使用 rebase 及 filter-branch 等工具来编写故事,怎么方便后来的读者就怎么写。

总的原则是,只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作,这样,你才能享受到两种方式带来的便利。

作者

Tsukimaru Oshawott

发布于

2024-05-07

更新于

2024-05-08

许可协议

评论