git是一个分布式版本控制系统,不同类型的版本控制软件还有svn,mercurial,vss,SourceAnywhere等。 而Github是一个集成了git的服务。
不管是使用Github,Coding还是Gitlab,我们都需要熟悉Git这一版本管理工具。本文简单介绍Git的工作原理,并总结了一些常用的git指令,冲突解决等,以便自己查看。
基本介绍
(图片均来自网络)

从上图可以看出git的组成和基本指令。git在本地的包括工作区,暂存区,以及本地仓库,stash。远端仓库就是Github,Coding,Gitlab等工具。
Git的存储方式
因为每一个版本之间可能有重叠,为了节省空间,git不是将每一个独立存放,而是以快照的形式存放。如下图所示:
Git分支
一般有两类分支:
- Merge分支(通常为master分支):Merge分支是为了可以随时发布release而创建的分支,可以使用Jenkins之类的CI工具进行自动化编译以及测试。
- Topic分支:用来进行功能开发的
HEAD
HEAD指向的是现在使用中的分支的最后一次更新。通常默认指向master分支的最后一次更新。通过移动HEAD,就可以变更使用的分支。
我们经常需要根据一个提交去查找它的祖先提交,如查找 HEAD 的第三个祖先提交。 这时就可以用到Git 中的 ~ 和 ^,其具体用法见文章。
分支规范
git上的分支命名规范
A successful Git branching model:

分支合并
在 git 中合并分支有两种选择:merge 和 rebase。
merge



rebase
4 以补丁的形式打到 3 上,形成了新的提交 4’。

rebase类似于打补丁。rebase的时候,修改冲突后的提交不是使用commit命令,而是执行rebase命令指定 –continue选项。若要取消rebase,指定 –abort选项。
但是,无论哪一种,都有可能产生冲突。
两种方法区别:
- merge
保持修改内容的历史记录,但是历史记录会很复杂。
- rebase
历史记录简单,是在原有提交的基础上将差异内容反映进去。
因此,可能导致原本的提交内容无法正常运行。
Git合并及冲突解决
冲突发生一般由于对同一个文件的修改不一致时。当有冲突发生时,一般需要手动合并冲突(也可以借助软件,如smartgit)。冲突标示一般为:
1 2 3 4 5
| <<<<<<<HEAD 本地仓库内容 ======= 远程仓库内容 >>>>>>>
|
手动合并后需要并删除标示行。
可能发生冲突的情况时:
Git常用指令
此处总结一些常用的Git指令,一以便查用。
初始
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| # 第一次安裝git之後,先設定自己的名字與信箱,因為Git用名字與信箱來分辨貢獻者 git config --global user.name "First Last" git config --global user.email "user@example.com"
# 初始化,使當前目錄成為git目錄 git init # 加上專案的說明文件(非必要) touch README.md # 加入暫存區 git add README.md # 提交到本地容器 git commit -m "initial commit"
# 將本地的repository上傳到遠端(如github)的repository # 將遠端容器命名為origin git remote add origin <URL> # 從本地端的master branch上傳到origin的master branch git push -u origin master
# 从远端仓库克隆到本地 git clone <URL>
|
远端数据库操作
1 2 3 4 5
| git pull # 取得远程数据库的最新历史记录。取得的提交会导入到没有名字的分支,这个分支可以从名为FETCH_HEAD的退出。 git fetch git push git clone <URL>
|
Git记录查看
1 2 3
| # 显示git flow # 指定--graph选项,能以文本形式显示更新记录的流程图。指定--oneline选项,能在一行中显示提交的信息。 $ git log --graph --oneline
|
Git分支(branch)
1 2 3 4 5 6 7 8 9 10 11 12 13
| git branch # 列出本地分支(前方有星號的為目前所在分支) git branch -r # 列出遠端分支 git branch -a # 列出所有分支(本地+遠端) git show-branch # 列出本地分支所包含的(有差異的)commit git branch [branchname] [commit] # 在指定commit上建立分支 git branch -d [branchname] # 刪除指定分支 git branch -m [old-name] [new-name] # 重新命名分支 git branch [new-branch] [old-branch] # 由old-branch複製出新分支
git checkout [branch] # 切換到指定分支 git checkout [commit] # 也可以切換到任何commit # 若commit不在任何branch上,用 git branch 查看時,會顯示 (no branch) git checkout -b [new-branch] # 建立並切換到該分支(從目前分支複製)
|
stash
还未提交的修改内容以及新添加的文件,留在索引区域或工作树的情况下切换到其他的分支时,修改内容会从原来的分支移动到目标分支。
但是如果在checkout的目标分支中相同的文件也有修改,checkout会失败的。这时要么先提交修改内容,要么用stash暂时保存修改内容后再checkout。
stash是临时保存文件修改内容的区域。stash可以暂时保存工作树和索引里还没提交的修改内容,您可以事后再取出暂存的修改,应用到原先的分支或其他的分支上。
使用時機:
- 你不得不修改一個緊急Bug,你可以先把目前工作目錄的變更丟到stash,這時候你的工作目錄和上次剛提交內容的狀況一樣,等到修完Bug後再把stash中剛剛做到一半的東西還原以繼續
- 今天的工作時間結束後,還有未完成的部分
- pull到一個不乾淨的樹而不用merge
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| git stash # 將目前把目前工作區的修改丟到stash裡 git stash save [message] # 將目前把目前工作區的修改丟到stash裡 git stash pop # 取出最新放入的一筆修改,並從stash中移除(若有衝突時會保留) git stash apply # 將最新投入的一筆修改套用在工作目錄上 git stash drop # 從stash中移除最新的一筆修改 git stash show [stashName] # 列出某一筆stash的修改內容 # 命名:最新的為 stash@{0}, 以此類推 git stash show -p [stashName] # 列出某一筆stash的詳細變更 # 命名:最新的為 stash@{0}, 以此類推 git stash list # 列出所有在stash的修改 git stash [file] # 將檔案丟進stash git stash clear # 清空stash git stash branch [branchName] # 用最新一筆stash新增branch git stash -p # 挑選要暫存的修改 git stash --includev # 同時暫存尚未在版本控制中的檔案(也就是從來沒被add過的檔案)
|
Git合併(merge)
1 2 3 4
| git merge [branch/commit] # 將指定的版本合併到目前所在的分支 # 也就是說,只有目前的分支會被影響! # 该命令将指定分支导入到HEAD指定的分支。
|
產生衝突時:先用git diff/status查看,修改后再提交
Git比較
1 2 3 4 5 6 7 8 9
| git diff [commit] # 比較指定版本和當前目錄的差別(不包含staging area)(預設為HEAD) git diff # 比較目前版本與工作目錄的不同([commit]=HEAD) git diff --cached/--staged [commit] # 比較暫存區(staging area)與指定版本(預設是HEAD)的不同 git diff [commit] [commit] # 比較兩個版本的差別 git diff [...] [filename] # 比較特定檔案差異 git diff -S[string] # 只列出變更中,有包含string字串的差異 git diff --stat # 差異資訊(只顯示檔名和行數) git diff -w # 不將空白視為變更 git diff [version1]:[file1] [version2]:[file2] # 比較兩個版本的指定檔案
|
Git标签
Git可以使用2种标签:轻标签和注解标签。打上的标签是固定的,不能像分支那样可以移动位置。
一般情况下,发布标签是采用注解标签来添加注解或签名的。轻标签是为了在本地暂时使用或一次性使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| # 添加轻标签 $ git tag <tagname> # 显示标签列表 $ git tag # 显示包含标签资料的历史记录 $ git log --decorate
# 添加注解标签 $ git tag -a <tagname> # 显示标签的列表和注解 $ git tag -n
# 删除标签 $ git tag -d <tagname>
|
改写提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| # e.g. $ git reset HEAD^ # 回退所有内容到上一个版本 $ git reset HEAD^ hello.php # 回退 hello.php 文件的版本到上一个版本 $ git reset 052e # 回退到指定版本
# 修改最近的提交 $ git commit --amend # 取消过去的提交(否定而非删除) $ git revert HEAD # 遗弃提交(删除) $ git reset --hard HEAD~~ # 还原到resset之前的状态 $ git reset --hard ORIG_HEAD # 提取提交:从其他分支复制指定的提交,然后导入到现在的分支。 $ git cherry-pick [commit]
# 汇合提交:两个提交就合并成一个提交 $ git rebase -i HEAD~~ # 指令会打开文本编辑器,将第二行的“pick”改成“squash”,然后保存并退出。然后执行: $ git commit --amend $ git rebase --continue
# 把分支上的所有提交都汇合到master上 $ git checkout master $ git merge --squash [branchName]
|
模式说明:
| 模式名称 |
HEAD的位置 |
索引 |
工作树 |
| soft |
修改 |
不修改 |
不修改 |
| mixed |
修改 |
修改 |
不修改 |
| hard |
修改 |
修改 |
修改 |
git reset –hard 操作后的数据恢复
第三方平台使用
添加SSH Key到远端服务器
- 打开terminal,输入命令
ls -al ~/.ssh,检查是否显示有id_rsa.pub或者id_dsa.pub存在,如果存在请直接跳至第3步。
- 在bash中输入ssh-keygen -t rsa -C ”yourEmail@example.com”
- 打开id_rsa.pub文件,并且复制全部内容
- 打开第三方平台账户,添加SSH Keys
就此,就可以使用ssh链接免密码上传本地仓库到远端仓库,或反之。
使用pycharm开发代码上传到GitLab和GitHub
References
浅析 Git 思想和工作原理
图解Git
Git常用指令
使用原理视角看 Git
GitLab 多人协同合作开发流程
Git &Gitlab协同流程
猴子都能懂的git入门(讲得蛮清晰也很完整的一个教程)