在学校,或许凭借一个人的力量就能负责整个项目的开发到上线。但是在在公司,因为项目的复杂性和紧急性,一个项目的往往是由多个人实现,此时就有一个问题,代码提交和代码合并。git和svn,这篇文章来讲讲git的原理和使用
version版本控制
git的账号配置
创建git仓库
git的原理
文件操作命令
分支操作命令
version版本控制
版本控制(Revision control)是一种在开发的过程中用于对文件、目录或工程等内容的修改历史,方便查看更改历史记录,备份及以便恢复以前版本的技术
没有进行版本控制或者版本控制本身缺乏正确的管理,在软件开发过程中将会引入很多问题,如软件代码的一致性、软件内容的冗余、软件开发过程中的并发性、软件源代码的安全性,以及软件的整合等问题
git的账号配置
配置名字和邮件地址
# git config --global user.name "hello lwl" # git config --global user.email lwl@csc.com // 查看系统config # git config --system --list // 查看当前用户(global)配置 # git config --global --list // 查看当前仓库配置信息 # git config --local --list
创建git仓库
// 在当前目录新建一个Git代码库 # git init // 克隆一个项目和它的整个代码历史(版本信息) # git clone [git@github.com:cscsss/learnHome.git]
git的原理
项目文件(Directory):使用Git管理的一个目录,也就是一个仓库,包含我们的工作区(WorkSpace)和 Git的管理空间(.git)
工作区(Workspace):就是平时存放项目代码的地方,一个文件夹而已
git管理空间(.git):存放Git管理信息的目录,初始化仓库的时候自动创建。里面又包含暂存区(Index/Stage)和 本地仓库(Repository)
暂存区(Index/Stage):用于存放你的临时改动信息,保存即将提交到文件列表信息。可用于保存/恢复 WorkSpace 中的临时状态
本地仓库(Repository):这里面存放你提交到所有版本的数据。其中HEAD指向最新放入仓库的版本
远程仓库(Remote):托管代码的服务器,和本地仓库作用类似,不过它是公共的
状态转移流程
未跟踪(Untracked): 此文件仅仅在 workspace 中,但并没有加入到 git 仓库,不参与版本控制。通过 git add 状态变为 Staged
文件已经入库(Unmodify): 未修改,即版本仓库中的文件快照内容与 workspace 中完全一致。这种类型的文件有两种变化,如果它被修改,而变为 Modified。如果使用 git rm 移出版本库,则成为 Untracked 文件
文件已修改(Modified): 仅仅是修改, 并没有进行其他的操作。通过 git add 可进入暂存 Staged 状态,使用 git checkout 则丢弃修改过,返回到 unmodify 状态,这个 git checkout 即从库中取出文件,覆盖当前修改
暂存状态(Staged): 执行 git commit 则将修改同步到仓库中,这时库中的文件和 workspace 文件又变为一致,文件为 Unmodify 状态。执行git reset branchName fileName取消暂存。文件状态恢复为 Modified图片
文件操作命令
查看文件状态
// 查看所有文件状态 # git status // 查看指定文件状态 # git status [fileName]
添加文件与目录
// 添加指定文件到暂存区 # git add [file1] [file2] ... // 添加指定目录到暂存区,包括子目录文件 # git add [dir]
移除文件与目录
// 将文件从暂存区和工作区中删除 # git rm <fileName> // 将 fileName 从暂存区删除文件,仍保留在当前工作目录中 # git rm --cached <fileName>
文件提交 git commit
// 将暂存区文件提交到本地仓库区,message为说明信息 # git commit -m [message] // 将暂存区的指定文件 fileName 提交到本地仓库 # git commit [fileName] -m [message] // 追加漏提交的暂存区文件。等价 git add . + git commit -m 'message' # git commit --amend -m [message]
查看文件状态及历史 git log
# git log //查看提交历史 # git log --oneline //以精简模式显示查看提交历史 # git log -p <fileName> //查看指定文件的提交历史 # git blame <fileName> //以列表方式查看指定文件的提交历史
git diff 比较差异
// 显示暂存区和工作区的全部差异 # git diff // 显示 filepath 路径文件中,工作区与暂存区的差异 # git diff filePath // 显示在工作区 filePath 文件与 HEAD 分支的差异 # git diff HEAD filePath // 显示在工作区的 filePath 文件与某次提交 commitId 的差异 # git diff commitId filePath
git reset 代码回退
有时提交了一些错误代码,我们想回滚怎么办,可以使用 git reset 重设置代码版本号。git reset 有三种模式 。soft、mixed、hard
// git reset [--soft | --mixed | --hard] [HEAD] // git reset [--soft | --mixed | --hard] [commit] # git reset –hard HEAD~3 //会将最新的3次提交全部重置,就像没有提交过一样 # git reset 003444c77bae2b0874be17b81a829cfb1237d9ce //重置到003444c7
--hard 模式
重置 HEAD 在当前分支到某次 commit 时,工作目录里的新改动和已经 add 到 stage 暂存区的新改动会全都消失。工作目录(workspace)、暂存区(index/stage)及本地仓库(repository)重置成目标 commit 的內容,所以效果看起来等同于清空暂存区和工作区
--soft 模式
--soft 模式在重置 HEAD 时,会保留工作目录和暂存区中的内容,并把重置 HEAD 所带来的新的差异放进暂存区,保留工作目录(workspace)和暂存区(index/stage)的内容,只让 repository 中的内容和 reset 节点保持一致,原节点和 reset 节点之间的「差异变动」会放入暂存区中(index/stage)
--mixed 模式图片git reset 如果不加参数,那么默认使用 --mixed 参数。mixed 模式会保留 工作目录(workspace)的內容,但会将暂存区(index/stage) 和 Repository 中的內容重置成 reset 节点一致,因此原节点和 reset 节点之间的「差异变动」会放入工作目录(workspace)
git revert
如果我们想撤销之前的某一版本,但是又想保留 commitId 提交之后的版本
# git revert -n commitId
分支操作命令
新建分支
// 基于当前分支新建一个分支,并且切换到新的分支 lwl # git checkout -b lwl // 基于远程分支 originBranch 并新建分支 csc # git checkout -b csc originBranch // 新建一个 csc 分支,但是仍停留在原来分支 # git branch csc // 切换到 csc 分支 # git checkout csc
git push
~~ 将本地分支的更新全部推送到远程仓库 master 分支 # git push origin master ~~ 删除远程 branchname 分支 # git push origin -d <branchName>
删除分支
# git branch -D <branchname> ~~ 删除本地 dev1 分支 # git branch -D dev1
分支合并
git-merge 命令是用于从指定的commit(s)合并到当前分支的操作
# git merge branchName //当前分支和 branchName 合并 # git merge -m <msg> <commit> //当前分支和 branchName commit及之前的提交合并 # git merge --abort // 取消合并
当产生合并冲突时,该部分会以<<<<<<<, =======和 >>>>>>>表示。在=======之前的部分是当前分支这边的情况,在=======之后的部分是对方分支的情况
解决完冲突的地方后使用git add加入到index中,然后使用git commit产生合并节点
git pull/git fetch
git fetch 可以拉取远程仓库的代码
~~ 拉取所有远端的最新代码 # git fetch --all ~~ 拉取远程最新 master 分支代码(指定 master 分支) # git fetch origin master
git pull。它不仅会拉取远程分支,还会合并远端和本地代码,即:git pull = git fetch + git merge
~~ 拉取远程仓库分支,更新并合并到本地分支 # git pull ~~ 将远程 master 分支合并到当前本地 master 分支 # git pull origin master ~~ 将远程 master 分支合并到当前本地 lwl 分支,冒号后面表示本地分支 # git pull origin master:lwl
git rebase 合并
git rebase master 命令会把当前分支 curBranch 里的每个提交(commit)取消掉,并且把它们临时保存为补丁(patch)(这些补丁放到".git/rebase"目录中),然后把 curBranch 分支更新为 master 分支最新提交,最后把保存的这些补丁应用到 curBranch 分支上
在 rebase 的过程中,也许会出现冲突(conflict)。在这种情况,Git会停止rebase并会让你去解决 冲突;在解决完冲突后,用 git add 命令去更新这些内容的索引(index), 然后,你无需执行 git-commit,只要执行git rebase --continue
# git rebase branchName // branchName 合并到当前分支 # git rebase --continue // 解决冲突后继续合并 # git rebase --abort //取消合并 # git rebase -i HEAD~2 //合并提交 --- 2表示合并2个。也可以是3...
如果 git rebase master 之后。需要将当前分支 curBranch的代码移到 master。可以再次使用 git merge。此时合并后 master 的提交是一条线性 commit
git tag
tag 对应某次 commit, 是一个点,是不可移动的。branch 对应一系列commit,是很多点连成的一根线,有一个HEAD 指针,是可以依靠 HEAD 指针移动的。所以,两者的区别决定了使用方式,改动代码用 branch,不改动只查看用 tag
创建 tag 是基于本地分支的 commit,而且与分支的推送是两回事,就是说分支已经推送到远程了,但是 tag 并没有,如果要把 tag 推送到远程分支上,需要另外执行 tag 的推送命令
# git tag <tagName> //基于最新的 commitId 创建 tagName # git tag -a <tagName> <commitId> // 基于某次 commitId 创建 tagName # git push origin <tagName> //推送到远程仓库 # git push --tags //推送所有标签 # git tag -d <tagName> // 删除本地 tag # git push origin :refs/tags/<tagName> // 删除远程 tag
欢迎指正文中错误
参考文章
一个小时学会Git[1]
程序员必备基础:Git 命令全方位学习[2]
Git Reset 三种模式[3]