The Basics

查看git版本 **git --version**
**git init** 初始化,将文件夹变成repo,生成了.git文件夹
git status 查看状态

An untracked file is one that is not under version control.我们要主动告诉git把什么文件加到仓库
**git add <file>** 创建了文件的snapshot用来准备commit, 创建snapshot的过程叫staging
git add 可以添加多个文件 git add orange.html blue.html
image.png

**git commit** 将snapshot提交到 project history, 需要在编辑器中填写提交信息
**git commit -m "message"** 在命令行中添加提交信息

所以保存一个项目版本分2步:

  1. Staging. Telling Git what files to include in the next commit.
  2. Committing. Recording the staged snapshot with a descriptive message.

git add不会对repo造成什么实质影响,只有git commit才把snapshot保存到repo中,成为项目的safe version

image.png

**git log** 查看Repository History
**git log --oneline** 以简介的方式查看提交历史
**git log --oneline <filename>...** 后面还可以添加1个或多个文件名,查看指定文件的提交历史
q键退出log

a new commit refers to its parentcommit
image.png

Quick Reference

git init
Create a Git repository in the current folder.
git status
View the status of each file in a repository.
git add <file>
Stage a file for the next commit.
git commit
Commit the staged files with a descriptive message.
git log
View a repository’s commit history.
git config --global user.name "<name>"
Define the author name to be used in all repositories.
git config --global user.email <email>
Define the author email to be used in all repositories.

Undoing Changes

View an Old Revision

每个commit记录的都是项目的历史版本
使用git log --oneline 查看历史commit信息
image.png
如果要查看id为916856d的commit的内容,使用命令 **git checkout 916856d**
image.png
此时查看代码,会发现在 3d8d577做的修改都消失了, 项目版本切换到了916856d
此时git log 会发现3d8d577不见了
image.png
image.png

Return to Current Version

切换到历史本版后, 最新的版本(snapshot)去了哪里呢?
image.png
这是因为我们脱离了分支
使用命令 git checkout master 回到主分支, 就又能看到所有的commit快照了

Tag a release

给最新的版本打上标签, 这样我们就可以方便地使用标签名访问commit

  1. git tag -a v1.0 -m "Stable version of the website"

-a 代表 annotated tag
使用命令 git tag 可以查看所有的tag

git commit 前先 git status查看有哪些文件要提交是个好习惯

tag就相当于对应的commit的快捷方式,如果要查看这个commit,可以用tag代替commit id
git checkout v1.0

Undo committed changes

在v1.0后我们又做了些修改,并提交为 e4dcc5b
image.png
现在要撤销这次提交,使用命令 **git revert** e4dcc5b
image.png
会发现git并没有删除e4dcc5b, 而是生成了一个新的commit 383875f, 这个commit的内容和v1.0一模一样
所以,git revert的作用是将指定的commit回退到其上一个版本(通过产生新的commit的方式)

为什么要使用get revert生成新的commit记录而不是直接移除commit记录?
在团队协作中,删除commit记录是不推荐的

接下来我们又做一些修改,添加了dummy.html文件,修改了index.html
image.png
执行命令 **git reset --hard** , 撤销工作区和暂存区所有tracked文件的修改
发现index.html恢复成了最近一次commit的版本
git reset只作用在working directorystaging area,不会影响到committed snapshots
如果git reset不加参数,只会把staging area的文件变成unstaged

git reset —hard只能作用在tracked文件,dummy.html文件未受影响
使用命令 **git clean -f** 会删除所有untracked文件

git revert VS git reset:
The git reset command undoes changes to the working directory and the staged snapshot, while git revert undoes changes contained in committed snapshots.

Quick Reference

git checkout <commit-id>
View a previous commit.
git tag -a <tag-name> -m "<description>"
Create an annotated tag pointing to the most recent commit.
git checkout <tag-name>
View a previous commit.
git revert <commit-id>
Undo the specified commit by applying a new commit.
git reset --hard
Reset tracked files to match the most recent commit.
git clean -f
Remove untracked files.
git reset --hard / git clean -f
Permanently undo uncommitted changes.

Branches, Part I

Git version control由四部分组成:

  • The Working Directory
  • The Staged Snapshot
  • Committed Snapshots
  • Development Branches

In Git, a branch is an independent line of development.

View Existing Branches

查看分支: **git branch**
image.png
master是默认分支
*星号代表check out, 即工作区(working directory)显示的是这个分支的最新快照(snapshot)的内容

detached HEAD

image.png
The HEAD is Git’s internal way of indicating the snapshot that is currently checked out.
image.png
当head被detach, 我们就不能说我们在master分支上了
image.png
我的理解:
可以将HEAD和master都理解为指针, HEAD指向的快照就是当前工作区展示的内容, master指向分支最新的快照, 默认情况下HEAD和master是重合的

Create a New Branch

如果想试验一个新特性,可以先创建一个分支来写代码, 没问题了再合并到主分支
创建分支: **git branch crazy**
该命令会从当前HEAD所在节点开始创建新的分支

When git branch creates a branch, it uses the current HEAD as the starting point for the newbranch.

切换到分支:**git checkout crazy** 此时HEAD和crazy重合
image.png
在crazy分支上做些修改, 做一次commit, 则可以看到分叉 fork
image.png
git log 只会显示当前分支上的提交历史
image.png
image.png
从分支头部回溯到第一次提交都属于这个分支

Rename the rainbow

将crazy.html重命名为rainbow.html
image.png
**git rm crazy.html** 告诉git不再track crazy.html, 同时删除工作区的文件
image.png
git 很聪明地知道我们重命名了文件
image.png

Merge branch

image.png
假如当前分支如上图所示
先切换到master分支: git checkout master
将css分支合并到master分支: **git merge css**
image.png
因为master是css的祖先, 所以git只是简单地把master移到了和css相同的位置, 这叫做 fast-forward merge
此时master和css拥有一模一样的提交历史
删掉css分支: **git branch -d css**

Quick Reference

git branch
List all branches.
git branch <branch-name>
Create a new branch using the current working directory as its base.
git checkout <branch-name>
Make the working directory and the HEAD match the specified branch.
git merge <branch-name>
Merge a branch into the checked-out branch.
git branch -d <branch-name>
Delete a branch.
git rm <file>
Remove a file from the working directory (if applicable) and stop tracking the file.

Branches, Part II

master是stable branch, 其他分支可以称为topic branches

  • Create a new branch for each major addition to your project.
  • Don’t create a branch if you can’t give it a specific name.

用merge合并分叉的2个分支,会产生一个新的commit, 这叫做 3-way merge

  1. git checkout crazy
  2. git merge master

image.png
此时,crazy既能访问自己的历史节点,也能访问master的历史节点

再对文件做一些修改,使用如下命令:
**git commit -a -m "Add CSS stylesheet to rainbow.html"**
这个命令将git add和git commit -m合并了,-a表示将所有tracked文件添加到staging area

Stage all tracked files and commit the snapshot using the specified message.

当git merge产生冲突时
修改冲突的文件, git add 修改的文件
git commit不需要加-m, 因为git会自动生成merge信息
image.png
image.png
删除crazy和crazy-alt分支
删除未合并的分支要用 **git branch -D <branchname>**
image.png
image.png

Rebasing

image.png
用git merge合并分支, commit历史会变得很凌乱
Git提供了git rebase移动分支,改变其base(父节点)

新建一个文件夹about, 新建文件index.html
git add 可以添加文件夹

  1. git add about
  2. git commit -m "Add about section"

用于紧急更新的分支可以叫hotfix分支

image.png
当前分支如上图所示,执行命令:
**git checkout about**
**git rebase master** 意思是把about的base(基)改为master最前方
结果变成下图所示:
image.png
about分支的2次提交移动到了master的前面
image.png
git add还可以加路径, 例如: **git add about/me.html**

rebasing interactively

git rebase not only lets youmove branches around, it enables you to manipulate individual commits as you do so.
加入参数 -i

  1. git rebase -i master

image.png
可以调整顺序, 合并(squash) commit等等
git rebase会生成新的commit id
image.png
if you were to delete a line from the rebase listing, the associated commit wouldn’t be transferred to the new base, and its content would be lost forever.

Stop to Amend a Commit

**git rebase -i master**
image.png
将pick改为edit, 当git处理到这个commit时,会停下来让我们修改
image.png
对文件做出修改后

  1. git add about/mary.html
  2. git status
  3. git commit --amend

—amend是使用当前的staged commit替换掉旧的commit
此时我们仍然停在这个commit, 后面还有commit要处理,使用命令 **git rebase --continue** 继续
将about分支合并到master
因为master是about的base
所以可以直接用fast-forward merge

  1. git checkout master
  2. git merge about
  3. git branch -d about

这里用**git rebase about**也是一样的效果

Quick Reference

**git rebase <new-base>**
Move the current branch’s commits to the tip of , which can be either a branch name
or a commit ID.
**git rebase -i <new-base>**
Perform an interactive rebase and select actions for each commit.
**git commit --amend**
Add staged changes to the most recent commit instead of creating a new one.
**git rebase --continue**
Continue a rebase after amending a commit.
**git rebase --abort**
Abandon the current interactive rebase and return the repository to its former state.
**git merge --no-ff <branch-name>**
Force a merge commit even if Git could do a fast-forward merge.

Rewriting History

**git checkout -b new-pages** 创建并切换到new-pages分支

commit的原则:

  • Commit a snapshot for each significant addition to your project.
  • Don’t commit a snapshot if you can’t come up with a single, specific message for it.

**git rebase -i master**
image.png
**git reset --mixed HEAD~1** 撤销当前commit, 但工作区内容保持不变

接连做2次修改和commit

  1. git add red.html index.html
  2. git status
  3. git commit -m "Add red page"
  4. git add yellow.html index.html
  5. git status
  6. git commit -m "Add yellow page"
  7. git rebase --continue

成功地删除了Add new HTML pages这个commit, 添加了2个新的commit
image.png

Remove the Last Commit

**git reset --hard HEAD~1** 撤销当前commit, 工作区内容也恢复成上一个commit
不加参数—hard, 默认为—mixed, 工作区内容不会改变
image.png
实际上是将分支指针移动到了HEAD~1, 之后的commit就不可见了

git 用 reflog记录每次你对仓库的更改
使用命令 **git reflog** 查看
image.png
按空格键查看完整记录, 按q退出

Revive the Lost Commit

**git checkout 002926a** 将HEAD移动到被撤销的commit
image.png
**git checkout -b green-page**创建一个新的分支
image.png

Filter the Log History

查看2个分支的不同,使用 log-filtering语法
**git log new-pages..green-page**
这个命令会列出在green-page分支不在new-pages分支的commits

还可以用这个命令指定git log输出的条数
**git log HEAD~4..HEAD**
**git log HEAD~4..HEAD --oneline**
为此,Git提供了更简单的命令:
**git log -n 4**
**git log -n 4 --oneline**

Merge in the Revived Branch

git checkout master
git log HEAD..green-page --stat
因为此时HEAD移动到master了, 所以等价于git log master..green-page --stat
—stat表示显示commit的详细更改
image.png
将master与green-page合并(fast-forward merge)
git merge green-pagegit rebase green-page
image.png
删除2个分支
git branch -d new-pages
git branch -d green-page

It’s important to realize that Git uses the tip of a branch to represent the entire branch. That is to say, a branch is actually a pointer to a single commit—not a container for a series of commits.
image.png
The history is represented by the parent of each commit (designated by arrows), not the branchitself. So, to request a new branch, all Git has to do is create a reference to the current commit.
And, to add a snapshot to a branch, it just has to move the branch reference to the new commit.

Quick Reference

git reflog
Display the local, chronological history of a repository.
git reset --mixed HEAD~<n>
Move the HEAD backward commits, but don’t change the working directory.
git reset --hard HEAD~<n>
Move the HEAD backward commits, and change the working directory to match.
git log <since>..<until>
Display the commits reachable from but not from . These parameters can be
either commit ID’s or branch names.
git log --stat
Include extra information about altered files in the log output.