此文基于周莫烦大神@莫烦的视频,文章以及自己的一些心得。
1. Git介绍
Git 是一个分布式版本控制系统. 它的灵活性, 优越性使得它从2005年发布以来. 获得了越来越多的使用和支持.
当你已经成为码农, 或者已经在成为码农的路上;当你觉得代码太多;当你已经开始用日期或版本号命名的代码文件的时候,就需要用GitHub来管理你的代码。
文本文件 (.txt) 等;脚本文件 (.py) 等;各种基于文本信息的文件可以被Git管理,但是图片文件 (.jpg) 等;MS word (.doc) 等不能被管理。
2. Git版本管理
创建版本库 init
我们先要确定要把哪个文件夹里的文件进行管理. 比如说我桌面上的一个叫 Git 的文件夹. 然后在 Terminal (Windows 的 git bash) 中把当前目录调到这个文件夹Git.为了更好地使用 git, 我们同时也记录每一个施加修改的人. 这样人和修改能够对应上. 所以我们在 git 中添加用户名 user.name 和 用户 email user.email:然后我们就能在这个文件夹中建立 git 的管理文件了.
添加文件管理 (add)
因为这个文件夹中还没有任何的文件, 它返回出来一句话告诉我们已经建立了一个空的 git 管理库.
通常我们执行 $ ls 就能看到文件夹中的所有文件, 不过 git 创建的管理库文件 .git 是被隐藏起来的. 所以我们要执行这一句才能看到被隐藏的文件.
建立一个新的 1.py 文件,用touch 1.py。
现在我们能用 status 来查看版本库的状态。现在 1.py 并没有被放入版本库中 (unstaged), 所以我们要使用 add 把它添加进版本库 (staged):
如果想一次性添加文件夹中所有未被添加的文件, 可以使用这个:
$ git add .
提交改变 (commit)
我们已经添加好了 1.py 文件, 最后一步就是提交这次的改变, 并在 -m 自定义这次改变的信息(即creat 1.py这句话可以自己写的,表明这次你commit了什么变化):
工作流程
Git管理包括三个状态:untracked, unstaged(unmodified,modified)和staged.
Untracked意思是Git根本不知掉有这个文件的存在,所以要调用git add的语句将这个文件添加到Git里头,让Git知道要管理这个文件。
Staged的意思是你已经让Git知道要管理这个文件了,然后要Commit这个文件,即提交上传。
Unstaged的意思是,当你Commit之后,就到了这个阶段。然后你要修改了的话,你又要继续add和commit。
3.记录修改(diff & log)
在 git 中, 每一次提交(commit)的修改, 都会被单独的保存起来. 也可以说 git 的中的所有文件都是一次次修改累积起来的. 文件好比楼房, 每个 commit 记录 了盖楼需添加或者拿走的材料. 整个施工过程也被记录了下来.
修改记录 log
git log
查看版本库进行几次修改。
git status
如果我们对1.py文件进行一次修改
所以我们先把这次修改添加 (add) 到可被提交 (commit) 的状态, 然后再提交 (commit) 这次的修改:
再次查看 log, 现在我们就能看到 create 1.py 和 change 1 这两条修改信息了. 而且做出这两条 commit 的 ID, 修改的 Author, 修改 Date 也被显示在上面.
查看修改部分 diff
git diff
如果想要查看这次还没 add (unstaged) 的修改部分 和上个已经 commit 的文件有何不同, 我们将使用 $ git diff:
git diff -cached
如果你已经 add 了这次修改, 文件变成了 “可提交状态” (staged), 我们可以在 diff 中添加参数 --cached 来查看修改:
git diff HEAD
还有种方法让我们可以查看 add 过 (staged) 和 没 add (unstaged) 的修改, 比如我们再修改一下 1.py 但不 add:
4. 记录找回(reset)
git log --oneline
查看对该文件做了几次的修改。
git commit --amend --no-edit
# "--no-edit": 不编辑, 直接合并到上一个 commit
补前一个commit遗漏的文件
有时候我们总会忘了什么, 比如已经提交了 commit 却发现在这个 commit 中忘了附上另一个文件. 接下来我们模拟这种情况. 上节内容中, 我们最后一个 commit 是 change 2, 我们将要添加另外一个文件, 将这个修改也 commit 进 change 2. 所以我们复制 1.py 这个文件, 改名为 2.py. 并把 2.py 变成 staged, 然后使用 --amend 将这次改变合并到之前的 change 2 中.
git reset
有时我们添加 add 了修改, 但是又后悔, 并想补充一些内容再 add. 这时, 我们有一种方式可以回到 add 之前. 比如在 1.py 文件中添加一行改变:
补前一个add命令遗漏的文件
然后 add 去 staged 再返回到 add 之前:
然后 add 去 staged 再返回到 add 之前:
git reset --hard
在几个commit版本直接穿梭
每个 commit 都有自己的 id 数字号, HEAD 是一个指针, 指引当前的状态是在哪个 commit. 最近的一次 commit 在最右边, 我们如果要回到过去, 就是让 HEAD 回到过去并 reset 此时的 HEAD 到过去的位置.
git reset --hard HEAD^
回到上一个commit的版本
git reset --hard HEAD~2
回到上两个commit的版本
git reset --hard f1c6883
回到特定ID的commit版本
git reflog
查看到底对几个commit版本进行了操作,然后如果想回到最近的版本,可以用特定ID的方法回来。
5. 文件找回(checkout)
git checkout f1c6883 -- 1.py
让某个文件回到过去某个特定ID的状态
6.分支管理
分支(branch)
之前我们说编辑的所有改变都是在一条主分支master上进行的. 通常我们会把master当作最终的版本, 而开发新版本或者新属性的时候, 在另外一个分支上进行, 这样就能使开发和使用互不干扰了.
git log --oneline --graph
我们可以通过--graph来观看分支
git branch dev
创建一个叫dev的分支
git branch
查看当前分支
git checkout dev
当我们想把HEAD切换去dev分支的时候, 我们可以用到上次说的checkout
git checkout -b dev
使用checkout -b+ 分支名, 就能直接创建和切换到新建的分支
git branch -d dev
删除叫dev的分支
git commit -am"change 3 in dev"
就是git add和git commit -m的合并版本,一句话做了两句话做的事情
git merge dev
我们的开发版本dev已经更新好了, 我们要将dev中的修改推送到master中, 大家就能使用到正式版中的新功能了.但前提是当前branch已经切换到master下面。
git merge --no-ff -m"keep merge info"dev
要注意的是, 如果直接git merge dev, git 会采用默认的Fast forward格式进行merge, 这样merge的这次操作不会有commit信息.log中也不会有分支的图案. 我们可以采取--no-ff这种方式保留merge的commit信息.
merge 分支冲突
今天的情况是这样, 想象不仅有人在做开发版dev的更新, 还有人在修改master中的一些 bug. 当我们再merge dev的时候, 冲突就来了. 因为 git 不知道应该怎么处理merge时, 在master和dev的不同修改.
当创建了一个分支后, 我们同时对两个分支都进行了修改.
当我们想要merge dev到master的时候:
git 发现的我们的1.py在master和dev上的版本是不同的, 所以提示merge有冲突. 具体的冲突, git 已经帮我们标记出来, 我们打开1.py就能看到:
所以我们打开1.py然后手动把这些冲突的部分修改下。但是,要记住要git commit一下你修改后的文件。
rebase 分支冲突
一个更高级的合并方式rebase. 同样是合并rebase的做法和merge不一样.
假设共享的 branch 是branch B, 而我在branch A上工作, 有一天我发现branch B已经有一些小更新, 我也想试试我的程序和这些小更新兼不兼容, 我想合并, 这时就可以用rebase来补充我的分支branch B的内容. 补充完以后, 和后面那张图的merge不同, 我还是继续在C3上工作, 不过此时的C3的本质却不一样了, 因为吸收了那些小更新. 所以我们用C3'来代替.
可以看出rebase改变了C3的属性,C3已经不是从C1衍生而来的了. 这一点和merge不一样.merge在合并的时候创建了一个新的C5commit. 这一点不同, 使得在共享分支中使用rebase变得危险. 如果是共享分支的历史被改写. 别人之前共享内容的commit就被你的rebase修改掉了.
git rebase dev
将继承的分支改了
如果出现冲突,和上面merge的解决方式相同
临时修改 (stash)
想想有天在开开心心地改进代码, 突然接到老板的一个电话说要改之前的一个程序. 怎么办? 虽然还需要很久时间才能改进完自己的代码, 可我有强迫症, 又不想把要改的程序和自己改进代码的部分一起 commit 了.
这时 stash 就是我的救星了. 用 stash 能先将我的那改进的部分放在一边分隔开来. 再另外单独处理老板的任务.
git stash
在 dev 中的 1.py 中加上一行 # feel happy, 然后老板的电话来了, 可是我还没有改进完这些代码. 所以我就用 stash 将这些改变暂时放一边.
然后我们建立另一个 branch 用来完成老板的任务。。。
git stash list
查看在 stash 中的缓存
git stash pop
上面说明在 dev 中, 我们的确有 stash 的工作. 现在可以通过 pop 来提取这个并继续工作了.
7. GitHub
github 是一个大家都积极贡献的地方, 你可以和各种人合作创作. 也是开源的天堂~ 只要你愿意, 任何人都能下载, 或修改你的杰作.
网友评论