目录
1. Git and Github
Git是版本控制软件(version control system VCS),方便track changes to files,包括what changed, who changed it, and why。而Github是项目代码托管的平台,借助git来管理项目代码。
2. Git的目录结构
在桌面上新建一个目录,然后利用命令行在该目录下运行git init
命令即可完成git仓库的初始化。进入.git目录,便可以看到其中有很多的文件和文件夹,如下图
.git中核心文件:
- config文件: 该文件主要记录针对该项目的一些配置信息
- 设置你的用户名称和e-mail地址:
git config --global user.name "Your Name"
git config --global user.email your_email@example.com
如果希望在一个特定的项目中使用不同的名称或e-mail地址,可以在该项目中运行该命令而加–global标签。 - 是否以bare方式初始化:
git init –bare
方法创建一个裸仓库,这个仓库只保存git历史提交的版本信息,而不允许用户在上面进行各种git操作 - remote信息:命令
git remote add <shortname> <url>
将远程仓库唯一的URL<url>
映射成为在本地仓库中对远程仓库起的别名<shortname>
。
根据官方文档,一般把<shortname>
设置为origin
。这个别名只能在自己的本地仓库使用。在真正的远程仓库那边,远程仓库的名字是一个绝对唯一的URL。
- 设置你的用户名称和e-mail地址:
- objects文件夹: 该文件夹主要包含git对象。Git中的文件和一些操作都会以git对象来保存,git对象分为BLOB、tree和commit三种类型,例如git commit便是git中的commit对象,而各个版本之间是通过 版本树 来组织的,比如当前的HEAD会指向某个commit对象,而该commit对象又会指向几个BLOB对象或者tree对象。(详细请查看[1])
- HEAD文件: 该文件指明了git branch(即当前分支)的结果,比如当前分支是master,则该文件就会指向master。
- index文件: 该文件保存了暂存区域的信息(某种程度就是缓冲区(staging area))
- Refs文件夹: 该文件夹存储指向数据(分支)的提交对象的指针。其中heads文件夹存储本地每一个分支最近一次commit的sha-1值(也就是commit对象的sha-1值),每个分支一个文件;remotes文件夹则记录你最后一次和每一个远程仓库的通信,Git会把你最后一次推送到这个remote的每个分支的值都记录在这个文件夹中;tag文件夹则是分支的别名。
3. Branch的概念
git 中的分支,其实本质上仅仅是个指向 commit 对象的可变指针。在 git 中,HEAD是一个指向你正在工作中的本地分支的指针。
remote branch 分为:
- The actual branch on the remote repository
(e.g., remote repo at https://example.com/repo.git, refs/heads/master) - Your snapshot of that branch locally (stored under refs/remotes/…)
(e.g., local repo, refs/remotes/origin/master) - A local branch that might be tracking the remote branch
(e.g., local repo, refs/heads/master)
4. Git的结构和命令关系
Git的基本工作流程图:
4.1 Git Fetch
git fetch
是将远程仓库的最新内容拉到本地,用户在检查了以后决定是否合并到工作本机分支中。
命令:
$ git fetch <远程主机名> #这个命令将某个远程主机的更新全部取回本地
如果只想取回特定分支的更新,可以指定分支名:
$ git fetch <远程主机名> <分支名> #注意之间有空格
例如:
$ git fetch origin master
取回更新后,会返回一个FETCH_HEAD
,指的是某个branch在服务器上的最新状态,我们可以在本地通过它查看刚取回的更新信息:
$ git log -p FETCH_HEAD
$ git merge FETCH_HEAD #将拉取下来的最新内容合并到当前所在的分支中
4.2 Git Remote
更改仓库指向:
$ git remote set-url origin <url> #远程仓库的 https 或者 ssh
查看仓库指向:
$ git remote get-url origin
$ git remote prune origin # 删除 refs to the branches that don't exist on the remote
$ git fetch --prune # 同上
4.3 Git Branch
git branch #查看本地所有分支
git branch -r #查看远程所有分支
git branch -a #查看本地和远程的所有分支
git branch <branchname> #新建分支
git branch -d <branchname> #删除本地分支
git branch -D <branchname> #强制删除本地分支(提示此branch没有fully merge可强制删除)-D = --delete --force
git branch -d -r <branchname> #删除远程分支,删除后还需推送到服务器
git push origin:<branchname> #删除后推送至服务器
git branch -m <oldbranch> <newbranch> #重命名本地分支
git branch --set-upstream-to <>/feature_branch feature_branch
4.4 Git Checkout
# 以远端remote_branch分支的内容为基础,创建本地的new_local_branch分支
git checkout -b new_local_branch origin/remote_branch
# 在本地创建一个special分支用于跟踪远端的special分支并切换到本地special分支
git checkout --track origin/special
# 切换到本地分支localbranch1
git checkout localbranch1
# 创建新的本地分支newbranch,此分支内容与localbranch1一致
git checkout -b newbranch
设置已有的本地分支跟踪一个刚刚拉取下来(git fetch
)的远程分支(remote_branch),或者想要修改正在跟踪的上游分支
git branch --set-upstream-to <远程仓库名>/<远程分支名> <本地分支名>
4.5 Git Log
# 显示每次commit信息
git log --abbrev-commit
# 显示代码修改信息
git log --stat
4.6 Git Diff
当工作区有改动,缓存区为空,diff的对比是“工作区与最后一次commit提交的仓库的共同文件”;当工作区有改动,缓存区不为空,diff对比的是“工作区与缓存区的共同文件”。
# 用来比较文件之间的不同
git diff
4.7 Git Reset
git reset --hard <commit_id>
直接退回到<commit_id>
的版本,重置 HEAD 和branch的同时,重置stage区和工作目录里的内容。你的stage区和工作目录里的内容会被完全重置为和HEAD的新位置相同的内容。
$ git log --abbrev-commit
commit 998a30b0 (HEAD -> feature_branch1)
<message1>
commit 412bc661 (origin/feature_branch2, feature_branch2)
<message2>
$ git reset --hard HEAD^
HEAD is now at 412bc661 <message2>
$ git reset --hard 998a30b0
HEAD is now at 998a30b0 <message1>
$ git status
On branch feature_branch1
nothing to commit, working tree clean
git reset --soft <commit_id>
会在重置 HEAD 和 branch 时,保留工作目录和暂存区中的内容,并把重置 HEAD 所带来的新的差异放进暂存区。
$ git log --abbrev-commit
commit 998a30b0 (HEAD -> feature_1)
<message1>
commit 412bc661 (origin/feature_2, feature_2)
<message2>
commit be30cf90
<message3>
$ git reset --soft HEAD^^
HEAD is now at be30cf90 <message3>
# 这个是在缓存区的状态
$ git status
On branch feature_branch1
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: modified_files
$ git reset HEAD .
Unstaged changes after reset:
M modified_files
# 这个是在工作区的状态
$ git status
On branch feature_branch1
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: modified_files
no changes added to commit (use "git add" and/or "git commit -a")
# 先从缓存区中拉取版本还原,如果没有再到版本库中拉取还原
$ git checkout -- <file>
# 因为之前退回到没有add和commit的版本,即此时工作区有代码变动
# 经过上述代码,从缓存区中拉去版本还原,所以工作区还原
$ git status
On branch feature_branch1
nothing to commit, working tree clean
4.8 Git Push
$ git push <远程仓库名> <本地分支名>:<远程分支名>
一般Git使用者会省略<远程分支名>这个参数,所以Git会默认把<本地分支名>设置为<远程分支名>。
# 若当前分支曾经未被远程跟踪
$ git push --set-upstream <远程仓库名> <本地分支名>
5. Submodule
可以理解为一个单独的git,在git中的git。所以每次更新、提交都需要单独执行。
# 创建submodule
$ git submodule add <url>
# clone 一个repo里面包含submodule
$ git clone <repo-url>
$ git submodule update --init --recursive
<待添加>
6. SSH
简单说,SSH是一种网络协议,用于计算机之间的加密登录。如果一个用户从本地计算机,使用SSH协议登录另一台远程计算机,我们就可以认为,这种登录是安全的,即使被中途截获,密码也不会泄露。
$ ssh-keygen -t rsa -C email@email.com
$ cat ~/.ssh/id_rsa.pub
将显示的内容拷贝到github ssh setup里
参考
[1] https://www.cnblogs.com/yelbosh/p/7471979.html
[2] https://www.jianshu.com/p/c2ec5f06cf1a
[3] git远程仓库分支的各命令的具体解析(git remote add)