git的基本使用流程

关于git的基本理解

git:一种分布式版本控制系统

git保存的是每一次改动,而不是文件本身。


git有三个区:

工作区(Working Directory)

这个区就是你在电脑上创建项目的地方,文件的编辑修改都在这个区中进行。

暂存区(Stage Area)

暂存区存放的是待提交到repo的修改,当你使用git add命令时,就是把工作区的修改添加到暂存区。

版本库/仓库(Git Directory/Repository)

每次使用git commit命令,就是把暂存区中的内容全部提交到repo中。


关于分支:

新建分支默认是master。

master分支应该是一个稳定的,可用的应用,平时不在这个分支上工作。

当要添加新功能时,可从master分支新建一个分支,如feature分支,当新功能完成时,再合并到master分支上,这样,master分支始终是稳定可用的。

多人合作时,可以每个人在各自的分支上工作,时不时合并到同一个分支上,当功能完善时,再合并到master分支。

分支之间大概是这种感觉(假设A、B两个人开发):

branches

当master分支上的应用出现bug时,可以在master分支上新建一个bug分支,如issue-101,修复bug后再合并到master分支上,然后删除bug分支。

基本流程

假设你已经安装了git

以下考虑最基本的git使用流程,开发时遇到的情况很多,以下流程暂不列出删除、撤销、回退的步骤,后面再单独列出来。

暂不考虑多人合作与远程repo,后面再补充,因为了解了怎么自己玩git,也就明白怎么跟基友一起玩github了。

因此以下流程都是在本地进行,跟github啥的暂时没什么关系。

新建repo->修改文件->添加修改到暂存区->提交修改到repo->创建分支->修改文件->添加修改到暂存区->提交修改到repo->合并分支->解决冲突

创建bug分支->修复bug->合并分支

流程步骤

新建repo

在项目根目录下使用git init初始化git仓库

修改文件

我们在项目目录下新建一个hello.txt文件,里面输入内容hello world(注意不要用Windows自带的记事本创建、编辑)

然后输入git status,会看到输出了这些信息:

1
2
3
4
5
6
7
8
9
10
On branch master

Initial commit

Untracked files:
(use "git add <file>..." to include in what will be committed)

hello.txt

nothing added to commit but untracked files present (use "git add" to track)

这边git提示我们有一个Untracked file,可以用git add <file>来添加要提交的文件。

添加修改到暂存区

按照提示,我们输入git add hello.txt把文件添加到暂存区(使用git add .添加更改过的全部文件)

再次输入git status,这次看到输出信息:

1
2
3
4
5
6
7
8
9
On branch master

Initial commit

Changes to be committed:
(use "git rm --cached <file>..." to unstage)

new file: hello.txt

hello.txt已经被存放到暂存区了

提交修改到repo

使用git commit -m 'add hello.txt'来提交这个文件的更改

输出信息:

1
2
3
4
[master (root-commit) 88aa3e8] add hello.txt
1 file changed, 1 insertion(+)
create mode 100644 hello.txt

这时候,文件的更改已经提交到repo中。

创建分支

在master分支下:

git checkout -b feature创建并切换到feature分支

创建分支是git branch feature,创建feature分支

切换分支是git checkout feature,切换到feature分支

合并分支

我们切换到feature分支,git checkout feature

打开刚才的hello.txt

把内容修改成goodbye world

然后用git addgit commit命令提交到repo中

切换到master分支,在hello.txt文件结尾加上一行hello world again,然后提交

这时候,两个分支各有一个提交(commit)

我们切换到master分支git checkout master

然后把feature分支合并到master分支上,git merge --no-ff -m 'merge feature' feature

这时候会提示有冲突:

1
2
3
Auto-merging hello.txt
CONFLICT (content): Merge conflict in hello.txt
Automatic merge failed; fix conflicts and then commit the result.

git提示我们解决了冲突再把结果commit。

解决冲突

冲突在多人合作中应该是常有的事。

我们打开hello.txt,发现内容变成了这样

1
2
3
4
5
6
7
hello world
<<<<<<< HEAD
hello world again
=======
goodbye world
>>>>>>> feature

于是我们把hello.txt修改成:

1
2
hello world
goodbye world

然后提交

1
2
3
git add hello.txt
git commit -m 'fix conflict'
[master 40cd928] fix conflict

分支合并成功。

可以用git log --graph --pretty=oneline --abbrev-commit来查看合并的情况

1
2
3
4
5
6
7
*   40cd928 fix conflict
|\
| * 3cbd4df modified hello.txt
* | a40c0bc add "again"
|/
* 10fb7e4 add hello.txt

log的顺序是按时间顺序从下到上。

bug分支

假设现在master分支上发现了个bug,需要紧急修复,但你现在正在feature分支上工作

假设现在hello.txt的内容是:

1
2
3
4
hello world
goodbye world

feature branch unfinished work

现在feature分支上的功能还未完成,无法提交,但是需要修复bug。这时,就需要使用git stash保存工作现场。

于是,在feature分支上,输入git stash,看到输出信息:

1
2
Saved working directory and index state WIP on feature: 3cbd4df modified hello.txt
HEAD is now at 3cbd4df modified hello.txt

这时候,再输入git status,发现输出:

1
2
On branch feature
nothing to commit, working tree clean

现场已被保存,打开hello.txt,后面的那句feature branch unfinished work也不见了。

好,现在我们可以切换到master分支,并新建一个bug分支来修复这个bug了。

1
2
git checkout master
git checkout -b issue-101

在hello.txt中添加一行issue-101 bug fixed,提交到repo

然后切回master分支,把issue-101分支合并进来。

1
2
3
4
5
git add hello.txt
git commit -m 'bug fixed'

git checkout master
git merge --no-ff -m 'merge issue-101' issue-101

输出信息:

1
2
3
4
Merge made by the 'recursive' strategy.
hello.txt | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

合并完成,然后我们回到feature分支继续工作。

1
git checkout feature

但是现在hello.txt里面的内容还是

1
2
hello world
goodbye world

我们需要把之前未完成的工作现场恢复过来。

使用git stash list可以查看保存了哪些工作现场:

1
stash@{0}: WIP on feature: 3cbd4df modified hello.txt

可以看到,这边只有一条数据,我们可以使用git stash pop来恢复这个现场。

输出的信息:

1
2
3
4
5
6
7
8
9
10
On branch feature
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

modified: hello.txt

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (643bef60d9b9540f66675d2fe1e8d9ad9d35f4fd)

可以看到,hello.txt里面的feature branch unfinished work又回来了
并且在恢复现场后,Dropped refs/stash@{0} (643bef60d9b9540f66675d2fe1e8d9ad9d35f4fd)
删除了stash的内容。

如果有多条stash数据,可以用git stash apply来恢复,如

1
git stash apply stash@{0}

但是用这种方式,stash内容并不会被删除,如果要删除某条stash,用git stash drop

删除、撤销、回退

删除

删除文件

假设我们有个文件,已经commit到repo中了,需要删除。
为此,我们新建一个文本文件delete.txt来模拟这个文件,把它提交到repo中。

这时候我们可以用两种方法来删除delete.txt。

1、使用git rm delete.txt

执行这句之后,会输出一句rm 'delete.txt',这时候到工作区查看,会发现delete.txt已经不在工作区了。

输入git status,发现输出如下信息:

1
2
3
4
5
6
On branch feature
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

deleted: delete.txt

暂存区已经记录了删除delete.txt的操作,接下来只要git commit就可以把delete.txt从repo中删除了。

2、直接从工作区目录中删除delete.txt,然后git addgit commit提交修改。

删除分支

git branch -d <name>可以删除分支。

例如我们可以删除之前用来修bug的issue-101分支

1
git branch -d issue-101

执行后输出的信息:

1
Deleted branch issue-101 (was 5d97433).

git branch查看分支,输出信息中表示只剩master分支跟feature分支了。

如果要删除一个未合并的分支,默认git会报错,例如我们创建一个delete分支,在hello.txt中添加一行内容delete branch,然后进行一个commit

1
2
3
git checkout -b delete
git add hello.txt
git commit -m 'update delete branch'

然后切回master分支,删除delete分支

1
2
git checkout master
git branch -d delete

输出了一个error:

1
2
error: The branch 'delete' is not fully merged.
If you are sure you want to delete it, run 'git branch -D delete'.

git告诉你这个分支没被合并,如果确定要删除,使用git branch -D delete

执行git branch -D delete,成功删除。

这个操作通常用来删除做到一半后面计划不做了的功能分支。

撤销

场景:从工作区撤销

你在hello.txt中写下了新的一行:I prefer svn
这时候你还没执行git add
输入git status,会发现有个提示,(use "git checkout -- <file>..." to discard changes in working directory)

于是按照提示,执行git checkout -- hello.txt
再回去hello.txt看看,新增的那句话已经被撤销了。

实际上,git checkout所做的,就是把工作区的修改替换成暂存区的。


场景:从暂存区撤销到工作区

你在hello.txt中写下了新的一行:I prefer svn
执行了git add hello.txt,把修改添加到暂存区
这时候git会提示你,(use "git reset HEAD <file>..." to unstage)

说得很清楚了,于是我们执行git reset HEAD hello.txt

再执行git status查看,发现修改又回到了工作区。


场景:从repo中撤销

……,,,遇到这种情况,看接下来的 回退 吧

回退

概念:git中有个HEAD指针,指向当前分支的当前版本,当我们进行回退操作时,其实就是改变HEAD指针,使其指向不同的commit节点。

理解了这个概念,就知道,既然是移动HEAD指针,那我们就可以在任意commit节点间进行跳转,无论是之前的版本,还是回退到之前版本后,想要回到未来的版本,只要知道commit的id就可以跳转版本。

使用git reset HEAD --hard <commit_id>来回退。

类似10fb7e42c63586db6948f7a9221bafb32f19409d这样的就是一个commit id,也可以输入前面几位,只要跟其他id有区别就行,如10fb7e4

commit_id可以使用git reflog来查看。(使用git log不能看到回退后未来的commit id)

多人合作

看到这里,清楚了git的基本操作,包括分支与解决冲突,单人玩git应该可以了,那么多人合作,其实是类似的,处理好分支与冲突的解决,多人合作也是没问题的。

远程repo

github是目前流行的远程repo之一。具体使用就不细说了。
当对本地repo进行了修改,用git push命令推送到远程repo就行了,包括分支的改动。

如果别人对远程的repo进行了修改,或者自己在另一台电脑上进行之前的项目,用git pull拉取下来就行,这个过程中也可能遇到冲突。

几个命令

git init 初始化repo

git status 列出未被添加到暂存区与未被提交到repo的修改(经常使用这个命令,对文件的修改以及提交情况会比较清楚)

git add <file> 添加修改到暂存区

git commit -m '<msg>' 提交修改到repo,并附上说明

git push 推送到远程仓库

git pull 从远程仓库拉取更新,并与本地对应分支合并

git branch 查看本地分支

git branch -a 查看远程分支

git branch <branch_name> 创建分支

git checkout <branch_name> 切换分支

git checkout -b <branch_name> 新建并切换分支

git merge 合并分支

git stash 保存工作区工作现场

git stash list 查看stash

git stash pop 恢复最后一个stash并删除stash数据

git stash apply <stash> 恢复指定stash

git stash drop <stash> 删除指定stash

git rm <file> 将文件从工作区删除

git branch -d <branch_name> 删除分支

git branch -D <branch_name> 强制删除未合并分支

git checkout -- <file> 把修改从工作区撤销

git reset HEAD <file> 把修改从暂存区撤销到工作区

git reset HEAD --hard <commit_id> repo版本回退到某个commit

git log 查看commit历史

git reflog 查看每个操作的log

参考