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