相关文章
版本管理
github访问太慢解决方案
Material for git workshop
GitHub秘籍
安装-Git版本管理
Git官网安装说明
Linux 系统安装
# 如果你的 Linux 是 Ubuntu:
$ sudo apt-get install git-all# 如果你的 Linux 是 Fedora:
$ sudo yum install git-all
如果是其他Linux版本,可以直接通过源码安装。先从Git官网下载源码,然后解压,依次输入:./config,make,sudo make install这几个命令安装
第一个版本管理库-Git版本管理
创建版本库 (init)
添加文件管理 (add)
提交改变 (commit)
流程图
版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。
创建版本库
#确定版本管理的文件,比如说Github-files
mkdir Github-files
cd ~/Github-files
#记录每一个施加修改的人. 这样人和修改能够对应上. 所以我们在 git 中添加用户名 user.name 和 用户 email user.emailgit config --global user.name "bids"
git config --global user.email "bids@siat.ac.cn"
#查看是否完成添加user.name 和 user.email
git config user.name
git confit user.email
bids
bids@siat.ac.cn
#建立 git 的管理文件
cd ~/Github-files
git init
瞬间Git就把仓库建好了,而且告诉你是一个空的仓库(empty Git repository),细心的读者可以发现当前目录下多了一个.git的目录,这个目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。
如果你没有看到.git目录,那是因为这个目录默认是隐藏的,用ls -ah命令就可以看见。
添加文件管理 (add)
cd ~/Github-files
ls -a
#. .. .git
#建立一个新的1.py
touch 1.py
#用 status 来查看版本库的状态
git status# 输出
On branch master # 在 master 分支Initial commitUntracked files: (use "git add <file>..." to include in what will be committed)1.py # 1.py 文件没有被加入版本库 (unstaged)nothing added to commit but untracked files present (use "git add" to track)
现在 1.py 并没有被放入版本库中 (unstaged), 所以我们要使用 add 把它添加进版本库 (staged):
$ git add 1.py# 再次查看状态 status
$ git status# 输出
On branch masterInitial commitChanges to be committed:(use "git rm --cached <file>..." to unstage)new file: 1.py # 版本库已识别 1.py (staged)
如果想一次性添加文件夹中所有未被添加的文件, 可以使用这个:
$ git add .
提交改变 (commit)
我们已经添加好了 1.py 文件, 最后一步就是提交这次的改变, 并在 -m 自定义这次改变的信息
$ git commit -m "create 1.py"# 输出
[master (root-commit) 6bd231e] create 1.py1 file changed, 0 insertions(+), 0 deletions(-)create mode 100644 1.py
git commit命令,-m后面输入的是本次提交的说明,可以输入任意内容,当然最好是有意义的,这样你就能从历史记录里方便地找到改动记录。
为什么Git添加文件需要add,commit一共两步呢?因为commit可以一次提交很多文件,所以你可以多次add不同的文件
$ git add file1.txt
$ git add file2.txt file3.txt
$ git commit -m "add 3 files."
流程图
整个上述过程可以被这张 git 官网上的流程图直观地表现:
小结
初始化一个Git仓库,使用git init命令。
添加文件到Git仓库,分两步:
第一步,使用命令git add ,注意,可反复多次使用,添加多个文件;
第二步,使用命令git commit,完成。
记录修改(log & diff)-Git版本管理
修改记录 log
查看修改部分 diff查看 unstaged查看 staged (–cached)查看 staged & unstaged (HEAD)
修改记录 log
cd ~/Github-files
#查看修改记录,git log命令显示从最近到最远的提交日志
git log
sudo gedit 1.py
#添加
a=1
#git status命令可以让我们时刻掌握仓库当前的状态
git status# 输出
On branch master
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: 1.py # 这里显示有一个修改还没被提交no changes added to commit (use "git add" and/or "git commit -a")
所以我们先把这次修改添加 (add) 到可被提交 (commit) 的状态, 然后再提交 (commit) 这次的修改:
$ git add 1.py
$ git commit -m "change 1"# 输出
[master fb51216] change 11 file changed, 1 insertion(+) # 提示文件有一处添加
再次查看 log, 现在我们就能看到 create 1.py 和 change 1 这两条修改信息了. 而且做出这两条 commit 的 ID, 修改的 Author, 修改 Date 也被显示在上面.
$ git log# 输出
commit fb51216b081e00db3996e14edf8ff080fab1980a
Author: bids <bids@siat.ac.cn>
Date: Tue Nov 29 00:24:50 2017 +1100change 1commit 13be9a7bf70c040544c6242a494206f240aac03c
Author: Morvan Zhou <mz@email.com>
Date: Tue Nov 29 00:06:47 2016 +1100create 1.py
查看修改部分 diff
能看看具体修改了什么内容
git diff顾名思义就是查看difference,显示的格式正是Unix通用的diff格式.
如果删除一部分代码, 也会被记录上, 比如把 a = 1 改成 a = 2, 再添加一个 b = 1
a=2
b=1
查看 unstaged
查看这次还没 add (unstaged) 的修改部分
$ git diff# 输出
diff --git a/1.py b/1.py
index 1337a53..ff7c36c 100644
--- a/1.py
+++ b/1.py
@@ -1 +1,2 @@
-a = 1 # 删除了 a = 1
+a = 2 # 添加了 a = 2
+b = 1 # 添加了 b = 1
查看 staged --cached
已经 add 了这次修改, 文件变成了 “可提交状态” (staged), 我们可以在 diff 中添加参数 –cached 来查看修改:
$ git add . # add 全部修改文件
$ git diff --cached# 输出
diff --git a/1.py b/1.py
index 1337a53..ff7c36c 100644
--- a/1.py
+++ b/1.py
@@ -1 +1,2 @@
-a = 1
+a = 2
+b = 1
查看 staged & unstaged HEAD
还有种方法让我们可以查看 add 过 (staged) 和 没 add (unstaged) 的修改, 比如我们再修改一下 1.py 但不 add
a = 2
b = 1
c = b
目前 a = 2 和 b = 1 已被 add, c = b 是新的修改, 还没被 add
# 对比三种不同 diff 形式
$ git diff HEAD # staged & unstaged@@ -1 +1,3 @@
-a = 1 # 已 staged
+a = 2 # 已 staged
+b = 1 # 已 staged
+c = b # 还没 add 去 stage (unstaged)
-----------------------
$ git diff # unstaged@@ -1,2 +1,3 @@a = 2 # 注: 前面没有 +b = 1 # 注: 前面没有 +
+c = b # 还没 add 去 stage (unstaged)
-----------------------
$ git diff --cached # staged@@ -1 +1,2 @@
-a = 1 # 已 staged
+a = 2 # 已 staged
+b = 1 # 已 staged
保持这次修改, 全部 add 变成 staged 状态, 并 commit
$ git add .
$ git commit -m "change 2"# 输出
[master 6cc6579] change 21 file changed, 3 insertions(+), 1 deletion(-)
小结
要随时掌握工作区的状态,使用git status命令。
如果git status告诉你有文件被修改过,用git diff可以查看修改内容
回到从前 (reset)-Git版本管理
修改已 commit 的版本
回到过去 reset回到 add 之前回到 commit 之前
比如已经提交了 commit 却发现在这个 commit 中忘了附上另一个文件.
修改已 commit 的版本
最后一个 commit 是 change 2, 我们将要添加另外一个文件, 将这个修改也 commit 进 change 2. 所以我们复制 1.py 这个文件, 改名为 2.py. 并把 2.py 变成 staged, 然后使用 –amend 将这次改变合并到之前的 change 2 中.
$ git add 2.py
$ git commit --amend --no-edit # "--no-edit": 不编辑, 直接合并到上一个 commit
$ git log --oneline # "--oneline": 每个 commit 内容显示在一行# 输出
904e1ba change 2 # 合并过的 change 2
c6762a1 change 1
13be9a7 create 1.py
回到过去 reset
回到 add
之前
$ git add 1.py
$ git status -s # "-s": status 的缩写模式
# 输出
M 1.py # staged
-----------------------
$ git reset 1.py
# 输出
Unstaged changes after reset:
M 1.py
-----------------------
$ git status -s
# 输出
M 1.py # unstaged
回到 commit
之前
# 不管我们之前有没有做了一些 add 工作, 这一步让我们回到上一次的 commit
$ git reset --hard HEAD
# 输出
HEAD is now at 904e1ba change 2
-----------------------
# 看看所有的log
$ git log --oneline
# 输出
904e1ba change 2
c6762a1 change 1
13be9a7 create 1.py
-----------------------
# 回到 c6762a1 change 1
# 方式1: "HEAD^"
$ git reset --hard HEAD^ # 方式2: "commit id"
$ git reset --hard c6762a1
-----------------------
# 看看现在的 log
$ git log --oneline
# 输出
c6762a1 change 1
13be9a7 create 1.py
怎么 change 2 消失了!!! 还有办法挽救消失的 change 2 吗? 我们可以查看 $ git reflog 里面最近做的所有 HEAD 的改动, 并选择想要挽救的 commit id:
$ git reflog #记录的是所有的log
# 输出
c6762a1 HEAD@{0}: reset: moving to c6762a1
904e1ba HEAD@{1}: commit (amend): change 2
0107760 HEAD@{2}: commit: change 2
c6762a1 HEAD@{3}: commit: change 1
13be9a7 HEAD@{4}: commit (initial): create 1.py
重复 reset 步骤就能回到 commit (amend): change 2 (id=904e1ba)这一步了:
$ git reset --hard 904e1ba
$ git log --oneline
# 输出
904e1ba change 2
c6762a1 change 1
13be9a7 create 1.py
小结
HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,使用命令git reset –hard commit_id。
穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。
要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。
回到从前 (checkout 针对单个文件)-Git版本管理
之前我们使用 reset 的时候是针对整个版本库, 回到版本库的某个过去. 不过如果我们只想回到某个文件的过去, 又该怎么办呢?
改写文件 checkout
我们仅仅要对 1.py 进行回到过去操作, 回到 c6762a1 change 1 这一个 commit. 使用 checkout + id c6762a1 + – + 文件目录 1.py, 我们就能将 1.py 的指针 HEAD 放在这个时刻 c6762a1:
$ git log --oneline
# 输出
904e1ba change 2
c6762a1 change 1
13be9a7 create 1.py
---------------------
$ git checkout c6762a1 -- 1.py
这时 1.py 文件的内容就变成了:
a = 1
我们在 1.py 加上一行内容 # I went back to change 1 然后 add 并 commit 1.py:
$ git add 1.py
$ git commit -m "back to change 1 and add comment for 1.py"
$ git log --oneline# 输出
47f167e back to change 1 and add comment for 1.py
904e1ba change 2
c6762a1 change 1
13be9a7 create 1.py
可以看出, 不像 reset 时那样, 我们的 change 2 并没有消失, 但是 1.py 却已经回去了过去, 并改写了未来.
git checkout – file命令中的–很重要,没有–,就变成了“切换到另一个分支”的命令
删除文件
一般情况下,你通常直接在文件管理器中把没用的文件删了,或者用rm命令删了
rm test.txt
这个时候,Git知道你删除了文件,因此,工作区和版本库就不一致了,git status命令会立刻告诉你哪些文件被删除了:
$ git status
# On branch master
# Changes not staged for commit:
# (use "git add/rm <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# deleted: test.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
现在你有两个选择,一是确实要从版本库中删除该文件,那就用命令git rm删掉,并且git commit
$ git rm test.txt
rm 'test.txt'
$ git commit -m "remove test.txt"
[master d17efd8] remove test.txt1 file changed, 1 deletion(-)delete mode 100644 test.txt
现在,文件就从版本库中被删除了。
另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:
$ git checkout -- test.txt
git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。
小结
命令git rm用于删除一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容。
分支(branch)-Git版本管理
分支 图例
建立 dev 分支使用 branch 创建使用 checkout 创建
在 dev 分支中修改
将 dev 的修改推送到 master
分支 图例
之前我们说编辑的所有改变都是在一条主分支 master 上进行的. 通常我们会把 master 当作最终的版本, 而开发新版本或者新属性的时候, 在另外一个分支上进行, 这样就能使开发和使用互不干扰了
我们之前的文件当中, 仅仅只有一条 master 分支, 我们可以通过 –graph 来观看分支
$ git log --oneline --graph #命令可以看到分支合并图
# 输出
* 47f167e back to change 1 and add comment for 1.py
* 904e1ba change 2
* c6762a1 change 1
* 13be9a7 create 1.py
建立 dev 分支
使用 branch
创建
$ git branch dev # 建立 dev 分支
$ git branch # 查看当前分支# 输出dev
* master # * 代表了当前的 HEAD 所在的分支
当我们想把 HEAD 切换去 dev 分支的时候, 我们可以用到上次说的 checkout
$ git checkout dev #切换分支# 输出
Switched to branch 'dev'
--------------------------
$ git branch# 输出
* dev # 这时 HEAD 已经被切换至 dev 分支
master
使用 checkout
创建并且切换分支
使用 checkout -b + 分支名, 就能直接创建和切换到新建的分支
$ git checkout -b dev# 输出
Switched to a new branch 'dev'
--------------------------
$ git branch# 输出
* dev # 这时 HEAD 已经被切换至 dev 分支
master
git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:
$ git branch dev
$ git checkout dev
Switched to branch 'dev'
查看所以的分支
git branch -a
在 dev 分支中修改
dev 分支中的 1.py 和 2.py 和 master 中的文件是一模一样的. 因为当前的指针 HEAD 在 dev 分支上, 所以现在对文件夹中的文件进行修改将不会影响到 master 分支.
我们在 1.py 上加入这一行 # I was changed in dev branch, 然后再 commit:
$ git commit -am "change 3 in dev" # "-am": add 所有改变 并直接 commit
git log --oneline
git checkout master
git log --oneline
master 分支没有受到影响。
将 dev 的修改推送到 master
好了, 我们的开发板 dev 已经更新好了, 我们要将 dev 中的修改推送到 master 中, 大家就能使用到正式版中的新功能了.
首先我们要切换到 master, 再将 dev 推送过来.
$ git checkout master # 切换至 master 才能把其他分支合并过来$ git merge dev # 将 dev merge 到 master 中
$ git log --oneline --graph# 输出
* f9584f8 change 3 in dev
* 47f167e back to change 1 and add comment for 1.py
* 904e1ba change 2
* c6762a1 change 1
* 13be9a7 create 1.py
git log --oneline --graph
要注意的是, 如果直接 git merge dev, git 会采用默认的 Fast forward 格式进行 merge, 这样 merge 的这次操作不会有 commit 信息. log 中也不会有分支的图案. 我们可以采取 –no-ff 这种方式保留 merge 的 commit 信息.
$ git merge --no-ff -m "keep merge info" dev # 保留 merge 信息
$ git log --oneline --graph# 输出
* c60668f keep merge info
|\
| * f9584f8 change 3 in dev # 这里就能看出, 我们建立过一个分支
|/
* 47f167e back to change 1 and add comment for 1.py
* 904e1ba change 2
* c6762a1 change 1
* 13be9a7 create 1.py
删除分支
合并完成后,就可以放心地删除dev分支了:
$ git branch -d dev
Deleted branch dev (was fec145a).
删除后,查看branch,就只剩下master分支了:
$ git branch
* master
小结
Git鼓励大量使用分支:
查看分支:git branch
创建分支:git branch
切换分支:git checkout
创建+切换分支:git checkout -b
合并某分支到当前分支:git merge
删除分支:git branch -d
如果要丢弃一个没有被合并过的分支,可以通过git branch -D 强行删除
merge 分支冲突-Git版本管理
今天的情况是这样, 想象不仅有人在做开发版 dev 的更新, 还有人在修改 master 中的一些 bug. 当我们再 merge dev 的时候, 冲突就来了. 因为 git 不知道应该怎么处理 merge 时, 在 master 和 dev 的不同修改.
当创建了一个分支后, 我们同时对两个分支都进行了修改.
比如在:
master 中的 1.py 加上 # edited in master.
dev 中的 1.py 加上 # edited in dev.
在下面可以看出在 master 和 dev 中不同的 commit:
git checkout master
git log --oneline
# 这是 master 的 log
* 3d7796e change 4 in master # 这一条 commit 和 dev 的不一样
* 47f167e back to change 1 and add comment for 1.py
* 904e1ba change 2
* c6762a1 change 1
* 13be9a7 create 1.py
-----------------------------
git checkout dev
git log --oneline
# 这是 dev 的 log
* f7d2e3a change 3 in dev # 这一条 commit 和 master 的不一样
* 47f167e back to change 1 and add comment for 1.py
* 904e1ba change 2
* c6762a1 change 1
* 13be9a7 create 1.py
当我们想要 merge dev 到 master 的时候:
$ git branch
dev
* master
-------------------------
$ git merge dev# 输出
Auto-merging 1.py
CONFLICT (content): Merge conflict in 1.py
Automatic merge failed; fix conflicts and then commit the result.
git 发现的我们的 1.py 在 master 和 dev 上的版本是不同的, 所以提示 merge 有冲突. 具体的冲突, git 已经帮我们标记出来, 我们打开 1.py 就能看到:
a = 1
# I went back to change 1
<<<<<<< HEAD
# edited in master
=======
# edited in dev
>>>>>>> dev
所以我们只要在 1.py 中手动合并一下两者的不同就 OK 啦. 我们将当前 HEAD (也就是master) 中的描述 和 dev 中的描述合并一下.
a = 1
# I went back to change 1# edited in master and dev
然后再 commit 现在的文件, 冲突就解决啦.
$ git commit -am "solve conflict"
再来看看 master 的 log:
$ git log --oneline --graph# 输出
* 7810065 solve conflict
|\
| * f7d2e3a change 3 in dev
* | 3d7796e change 4 in master
|/
* 47f167e back to change 1 and add comment for 1.py
* 904e1ba change 2
* c6762a1 change 1
* 13be9a7 create 1.py
rebase 分支冲突-Git版本管理
什么是 rebase
一个更高级的合并方式 rebase. 同样是合并 rebase 的做法和 merge 不一样.
假设共享的 branch 是 branch B, 而我在 branch A 上工作, 有一天我发现branch B已经有一些小更新, 我也想试试我的程序和这些小更新兼不兼容, 我也我想合并, 这时就可以用 rebase 来补充我的分支branch B的内容. 补充完以后, 和后面那张图的 merge 不同, 我还是继续在 C3 上工作, 不过此时的 C3 的本质却不一样了, 因为吸收了那些小更新. 所以我们用 C3’ 来代替.
可以看出 rebase 改变了 C3 的属性, C3 已经不是从 C1 衍生而来的了.
所以需要强调的是 !!! 只能在你自己的分支中使用 rebase, 和别人共享的部分是不能用 !!!. 如果你不小心弄错了. 没事, 我们还能用在 reset 这一节 提到的 reflog 恢复原来的样子.
使用 rebase
master 和 dev 分支中都有自己的独立修改.
git checkout master
git log --oneline
# 这是 master 的 log
* 3d7796e change 4 in master # 这一条 commit 和 dev 的不一样
* 47f167e back to change 1 and add comment for 1.py
* 904e1ba change 2
* c6762a1 change 1
* 13be9a7 create 1.py
-----------------------------
git checkout dev
git log --oneline
# 这是 dev 的 log
* f7d2e3a change 3 in dev # 这一条 commit 和 master 的不一样
* 47f167e back to change 1 and add comment for 1.py
* 904e1ba change 2
* c6762a1 change 1
* 13be9a7 create 1.py
当我们想要用 rebase 合并 dev 到 master 的时候:
$ git branch# 输出dev
* master
-------------------------
$ git rebase dev # 输出
First, rewinding head to replay your work on top of it...
Applying: change 3 in dev
Using index info to reconstruct a base tree...
M 1.py
Falling back to patching base and 3-way merge...
Auto-merging 1.py
CONFLICT (content): Merge conflict in 1.py
error: Failed to merge in the changes.
Patch failed at 0001 change 3 in dev
The copy of the patch that failed is found in: .git/rebase-apply/patchWhen you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".
git 发现的我们的 1.py 在 master 和 dev 上的版本是不同的, 所以提示 merge 有冲突. 具体的冲突, git 已经帮我们标记出来, 我们打开 1.py 就能看到:
a = 1
# I went back to change 1
<<<<<<< f7d2e3a047be4624e83c1265a0946e2e8790f79c
# edited in dev
=======
# edited in master
>>>>>>> change 4 in master
这时 HEAD 并没有指向 master 或者 dev, 而是停在了 rebase 模式上:
$ git branch
* (no branch, rebasing master) # HEAD 在这devmaster
所以我们打开 1.py, 手动合并一下两者的不同.
a = 1
# I went back to change 1# edited in master and dev
然后执行 git add 和 git rebase –continue 就完成了 rebase 的操作了.
$ git add 1.py
$ git rebase --continue
再来看看 master 的 log:
$ git log --oneline --graph# 输出
* c844cb1 change 4 in master # 这条 commit 原本的id=3d7796e, 所以 master 的历史被修改
* f7d2e3a change 3 in dev # rebase 过来的 dev commit
* 47f167e back to change 1 and add comment for 1.py
* 904e1ba change 2
* c6762a1 change 1
* 13be9a7 create 1.py
临时修改 (stash)-Git版本管理
暂存修改
做其它任务
恢复暂存
想想有天在开开心心地改进代码, 突然接到老板的一个电话说要改之前的一个程序. 怎么办? 虽然还需要很久时间才能改进完自己的代码, 可我有强迫症, 又不想把要改的程序和自己改进代码的部分一起 commit 了.
这时 stash 就是我的救星了. 用 stash 能先将我的那改进的部分放在一边分隔开来. 再另外单独处理老板的任务.
暂存修改
假设我们现在在 dev 分支上快乐地改代码:
$ git checkout dev
在 dev 中的 1.py 中加上一行 # feel happy, 然后老板的电话来了, 可是我还没有改进完这些代码. 所以我就用 stash 将这些改变暂时放一边.
$ git status -s
# 输出M 1.py
------------------
$ git stash
# 输出
Saved working directory and index state WIP on dev: f7d2e3a change 3 in dev
HEAD is now at f7d2e3a change 3 in dev
-------------------
$ git status
# 输出
On branch dev
nothing to commit, working directory clean # 干净得很
做其它任务
然后我们建立另一个 branch 用来完成老板的任务:
$ git checkout -b boss# 输出
Switched to a new branch 'boss' # 创建并切换到 boss
然后苦逼地完成着老板的任务, 比如添加 # lovely boss 去 1.py. 然后 commit, 完成老板的任务.
$ git commit -am "job from boss"
$ git checkout master
$ git merge --no-ff -m "merged boss job" boss
merge 如果有冲突的话, 可以像上次那样 解决.
a = 1
# I went back to change 1
<<<<<<< HEAD# edited in master and dev=======
# edited in dev# lovely boss
>>>>>>> boss
通过以下步骤来完成老板的任务, 并观看一下 master 的 log:
$ git commit -am "solve conflict"
$ git log --oneline --graph
* 1536bea solve conflict
|\
| * 27ba884 job from boss
* | 2d1961f change 4 in master
|/
* f7d2e3a change 3 in dev
* 47f167e back to change 1 and add comment for 1.py
* 904e1ba change 2
* c6762a1 change 1
* 13be9a7 create 1.py
恢复暂存
轻松了, 现在可以继续开心的在 dev 上刷代码了.
$ git checkout dev
$ git stash list # 查看在 stash 中的缓存# 输出
stash@{0}: WIP on dev: f7d2e3a change 3 in dev
上面说明在 dev 中, 我们的确有 stash 的工作. 现在可以通过 pop 来提取这个并继续工作了.
$ git stash pop# 输出
On branch dev
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: 1.pyno changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (23332b7edc105a579b09b127336240a45756a91c)
----------------------
$ git status -s
# 输出M 1.py # 和最开始一样了
小结
修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;
当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场。
多人协作-Git版本管理
master分支是主分支,因此要时刻与远程同步;
dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;
bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;
feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。
多人协作的工作模式通常是这样:
首先,可以试图用git push origin branch-name推送自己的修改;
如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;
如果合并有冲突,则解决冲突,并在本地提交;
没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功!
如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令git branch –set-upstream branch-name origin/branch-name。
这就是多人协作的工作模式,一旦熟悉了,就非常简单。
小结
查看远程库信息,使用git remote -v;
本地新建的分支如果不推送到远程,对其他人就是不可见的;
从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;
在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致;
建立本地分支和远程分支的关联,使用git branch --set-upstream branch-name origin/branch-name;
从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。
标签管理-Git版本管理
Git的标签虽然是版本库的快照,但其实它就是指向某个commit的指针。
Git有commit,为什么还要引入tag?
“请把上周一的那个版本打包发布,commit号是6a5819e…”
“一串乱七八糟的数字不好找!”
如果换一个办法:
“请把上周一的那个版本打包发布,版本号是v1.2”
“好的,按照tag v1.2查找commit就行!”
tag就是一个让人容易记住的有意义的名字,它跟某个commit绑在一起。
在Git中打标签非常简单,首先,切换到需要打标签的分支上:
$ git branch
* devmaster
$ git checkout master
Switched to branch 'master'
然后,敲命令git tag 就可以打一个新标签:
$ git tag v1.0
默认标签是打在最新提交的commit上的。有时候,如果忘了打标签,比如,现在已经是周五了,但应该在周一打的标签没有打,怎么办?
方法是找到历史提交的commit id,然后打上就可以了:
$ git log --pretty=oneline --abbrev-commit
6a5819e merged bug fix 101
cc17032 fix bug 101
7825a50 merge with no-ff
6224937 add merge
59bc1cb conflict fixed
400b400 & simple
75a857c AND simple
fec145a branch test
d17efd8 remove test.txt
...
比方说要对add merge这次提交打标签,它对应的commit id是6224937,敲入命令:
$ git tag v0.9 6224937
再用命令git tag查看标签:
$ git tag
v0.9
v1.0
小结
命令git tag <name>用于新建一个标签,默认为HEAD,也可以指定一个commit id;
git tag -a <tagname> -m "blablabla..."可以指定标签信息;
git tag -s <tagname> -m "blablabla..."可以用PGP签名标签;
命令git tag可以查看所有标签。
操作标签
如果标签打错了,也可以删除:
$ git tag -d v0.1
Deleted tag 'v0.1' (was e078af9)
因为创建的标签都只存储在本地,不会自动推送到远程。所以,打错的标签可以在本地安全删除。
如果要推送某个标签到远程,使用命令git push origin :
$ git push origin v1.0
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git* [new tag] v1.0 -> v1.0
或者,一次性推送全部尚未推送到远程的本地标签:
$ git push origin --tags
Counting objects: 1, done.
Writing objects: 100% (1/1), 554 bytes, done.
Total 1 (delta 0), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git* [new tag] v0.2 -> v0.2* [new tag] v0.9 -> v0.9
如果标签已经推送到远程,要删除远程标签就麻烦一点,先从本地删除:
$ git tag -d v0.9
Deleted tag 'v0.9' (was 6224937)
然后,从远程删除。删除命令也是push,但是格式如下:
$ git push origin :refs/tags/v0.9
To git@github.com:michaelliao/learngit.git- [deleted] v0.9
Github-Git版本管理
建立 github 版本库
连接本地版本库
推送修改
建立 github 版本库
Create a new online repository
添加好了以后, 会出现下面的介绍, 你可以选择push an existing repository 的代码链接上你的本地版本库.
连接本地版本库
$ cd ~/Github-files
$ git remote add origin https://github.com/MorvanZhou/git-demo.git
$ git push -u origin master # 推送本地 master 去 origin
$ git push -u origin dev # 推送本地 dev 去 origin
推送修改
如果在本地再进行修改, 比如在 1.py 文件中加上 # happy github, 然后 commit 并推上去:
$ git commit -am "change 5"
$ git push -u origin master
参考文献
git - 简明指南
git - the simple guide
Git版本管理
Git 版本管理视频
Git教程-廖雪峰
Git - Quick Guide
Git - Tutorial
Pro Git与Git的参考文档
Github 的项目怎么引用另一个项目?
submodule 中文文档
submodule 实例教材
subtree用法参考