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两个人开发):
当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 | On branch master |
这边git提示我们有一个Untracked file,可以用git add <file>
来添加要提交的文件。
添加修改到暂存区
按照提示,我们输入git add hello.txt
把文件添加到暂存区(使用git add .
添加更改过的全部文件)
再次输入git status
,这次看到输出信息:
1 | On branch master |
hello.txt已经被存放到暂存区了
提交修改到repo
使用git commit -m 'add hello.txt'
来提交这个文件的更改
输出信息:
1 | [master (root-commit) 88aa3e8] add 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 add
跟git commit
命令提交到repo中
切换到master分支,在hello.txt文件结尾加上一行hello world again
,然后提交
这时候,两个分支各有一个提交(commit)
我们切换到master分支git checkout master
然后把feature分支合并到master分支上,git merge --no-ff -m 'merge feature' feature
这时候会提示有冲突:
1 | Auto-merging hello.txt |
git提示我们解决了冲突再把结果commit。
解决冲突
冲突在多人合作中应该是常有的事。
我们打开hello.txt,发现内容变成了这样
1 | hello world |
于是我们把hello.txt修改成:
1 | hello world |
然后提交
1 | git add hello.txt |
分支合并成功。
可以用git log --graph --pretty=oneline --abbrev-commit
来查看合并的情况
1 | * 40cd928 fix conflict |
log的顺序是按时间顺序从下到上。
bug分支
假设现在master分支上发现了个bug,需要紧急修复,但你现在正在feature分支上工作
假设现在hello.txt的内容是:
1 | hello world |
现在feature分支上的功能还未完成,无法提交,但是需要修复bug。这时,就需要使用git stash
保存工作现场。
于是,在feature分支上,输入git stash
,看到输出信息:
1 | Saved working directory and index state WIP on feature: 3cbd4df modified hello.txt |
这时候,再输入git status
,发现输出:
1 | On branch feature |
现场已被保存,打开hello.txt,后面的那句feature branch unfinished work
也不见了。
好,现在我们可以切换到master分支,并新建一个bug分支来修复这个bug了。
1 | git checkout master |
在hello.txt中添加一行issue-101 bug fixed
,提交到repo
然后切回master分支,把issue-101分支合并进来。
1 | git add hello.txt |
输出信息:
1 | Merge made by the 'recursive' strategy. |
合并完成,然后我们回到feature分支继续工作。
1 | git checkout feature |
但是现在hello.txt里面的内容还是
1 | hello world |
我们需要把之前未完成的工作现场恢复过来。
使用git stash list
可以查看保存了哪些工作现场:
1 | stash@{0}: WIP on feature: 3cbd4df modified hello.txt |
可以看到,这边只有一条数据,我们可以使用git stash pop
来恢复这个现场。
输出的信息:
1 | On branch feature |
可以看到,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 | On branch feature |
暂存区已经记录了删除delete.txt的操作,接下来只要git commit
就可以把delete.txt从repo中删除了。
2、直接从工作区目录中删除delete.txt,然后git add
,git 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 | git checkout -b delete |
然后切回master分支,删除delete分支
1 | git checkout master |
输出了一个error:
1 | error: The branch 'delete' is not fully merged. |
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