Git 版本管理

相关文章

版本管理
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’ 来代替.

1

这里写图片描述

这里写图片描述

这里写图片描述

可以看出 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用法参考

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/246810.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

tensorflow:Multiple GPUs

深度学习theano/tensorflow多显卡多人使用问题集 tensorflow中使用指定的GPU及GPU显存 Using GPUs petewarden/tensorflow_makefile tf_gpu_manager/manager.py 多GPU运行Deep Learning 和 并行Deep Learning&#xff08;待续&#xff09; Multiple GPUs 1. 终端执行程序…

Tensorflow一些常用基本概念与函数

参考文献 Tensorflow一些常用基本概念与函数 http://www.cnblogs.com/wuzhitj/archive/2017/03.html Tensorflow笔记&#xff1a;常用函数说明&#xff1a; http://blog.csdn.net/u014595019/article/details/52805444 Tensorflow一些常用基本概念与函数&#xff08;1&#…

ubuntu16.04 Nvidia 显卡的风扇调速及startx的后果

问题描述 #查看nvdia GPU 显卡状态 watch -n 10 nvidia-smi 发现显卡Tesla k40c的温度已经达到74&#xff0c;转速仅仅只有49%。 查看Tesla产品资料&#xff0c;Tesla K40 工作站加速卡规格 &#xff0c;可知 所以需要调整风扇速度来降温。 然而官方驱动面板里也没有了风扇调…

Python函数式编程-map()、zip()、filter()、reduce()、lambda()

三个函数比较类似&#xff0c;都是应用于序列的内置函数。常见的序列包括list、tuple、str map函数 map函数会根据提供的函数对指定序列做映射。 map函数的定义&#xff1a; map(function, sequence[, sequence, ...]) -> list map()函数接收两个参数&#xff0c;一个是函…

Kaggle : Using a Convolutional Neural Network for classifying Cats vs Dogs

数据下载 https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition/data Part 1 - Preprocessing #Package Requirements #!/usr/bin/python2 # -*- coding: UTF-8 -*- import cv2 # working with, mainly resizing, images import numpy as np …

李宏毅机器学习课程1~~~Introduction Regression

机器学习介绍 机器学习就是要找一个函数。 机器学习的三大要素框架&#xff1a;训练集&#xff0c;函数集&#xff08;模型集&#xff09;&#xff0c;损失函数集。 机器学习图谱 AI训练师的成长之路。 1. 梯度下降法的理解Gradient Descent 参数变化的方向就是损失函数减少的方…

李宏毅机器学习课程2~~~误差从哪里来?

Stanford机器学习—第六讲. 怎样选择机器学习方法、系统 误差来源 误差主要来自于偏差和方差。 数学上定义&#xff1a; 通过covariate X 预测 Y &#xff0c;我们假设存在如下关系&#xff1a; Y f(X) ϵ 满足正态分布均值为0 方差σϵ 模型预测错误定义为&#xff1a; …

李宏毅机器学习课程3~~~梯度下降法

梯度下降法描述 梯度下降法是为了找到最优的目标函数&#xff0c;寻找的过程就是沿着损失函数下降的方向来确定参数变化的方向。参数更新的过程就是一个不断迭代的过程&#xff0c;每次更新参数学到的函数都会使得误差损失越来越小&#xff0c;也就是说学习到的参数函数越来越逼…

李宏毅机器学习课程4~~~分类:概率生成模型

分类问题用回归来解决&#xff1f; 当有右图所示的点时&#xff0c;这些点会大幅改变分类线的位置。这时候就会导致整体的回归结果变差。当把多分类当成回归问题&#xff0c;类别分别为1&#xff0c;2,3,4……&#xff0c;因为回归的问题是预测具体的值&#xff0c;这样定义类别…

李宏毅机器学习课程5~~~分类:逻辑回归

Function Set 不同的w&#xff0c;b来确定不同的函数&#xff0c;这样就组成了函数集合&#xff0c;不同的w&#xff0c;b可以来表达不同的分布函数。 Good of a Function 变换表达形式 两个Bernoulli distribution的交叉熵。所谓交叉熵&#xff0c;是用来刻画两个分布的相似性…

李宏毅机器学习课程6~~~深度学习入门

深度学习历史 深度学习经典步骤 神经网络的符合标记含义 Wij 代表的是从神经元&#xff4a;到神经元&#xff49;&#xff0c;这样写的目的是便于表达&#xff0c;否则最后的表达式子就是Wij的转置&#xff0c;细节见下面。 每个神经元的偏执值组成一个向量&#xff42; 单个神…

李宏毅机器学习课程7~~~反向传播

到底为什么基于反向传播的纯监督学习在过去表现不佳&#xff1f;Geoffrey Hinton总结了目前发现的四个方面问题&#xff1a; 带标签的数据集很小&#xff0c;只有现在的千分之一. 计算性能很慢&#xff0c;只有现在的百万分之一. 权重的初始化方式笨拙. 使用了错误的非线性模型…

李宏毅机器学习课程8~~~keras

keras keras示例 确定网络结构 确定损失函数 确定训练网络参数 batchsize与运算时间&#xff0c;平行运算&#xff0c;可以缩简运算时间。batchsize不能太大&#xff0c;这是由于内存的关系。此外&#xff0c;batchsize太大容易陷入局部极值点或者鞍点。batchsize&#xff1d;&…

李宏毅机器学习课程9~~~深度学习技巧

Recipe of Deep Learning Overfitting overfitting的判断是要训练误差与测试误差做比较。这个56-layer的网络在训练集上都没有训练好&#xff0c;说白了就是有点欠拟合。所以仅仅依靠测试集上的结果来判断56-layer比20-layer overfitting是不合理的。 更多理解见 Overfitting…

Liner(分段线性插值)

第一次写微博&#xff0c;记录自己的学习历程~~~~欢迎大家一起探讨~~~~ 分段线性插值故名思议就是说把给定样本点的区间分成多个不同区间&#xff0c;记为[xi,xi1]&#xff0c;在每个区间上的一次线性方程为&#xff1a; 关于其证明&#xff1a; 分段线性插值在速度和误差取得…

在linux设置回收站 - 防止失误操作造成数据清空,并定期清理

安装trash sudo apt-get install trash-chi 原理 执行trash命令后&#xff0c;是将文件移动了用户的回收站&#xff0c;每个用户的回收站路径为$HOME/.local/share/Trash&#xff0c;比如用户asin的回收站位于/home/asin/.local/share/Trash&#xff0c;用户root的回收站位于…

Spline(三次样条插值)

关于三次样条插值&#xff0c;计算方法比较复杂&#xff0c;但是静下心来仔细研究也是可以理解的。 本文借鉴文章来源&#xff1a;http://www.cnki.com.cn/Article/CJFDTotal-BGZD200611035.htm 定义&#xff1a; 简单来说就是给定了一些在区间[a,b]的数据点{x1,x2,x3.....xn…

李宏毅机器学习课程10~~~卷积神经网络

卷积的意义 数字图像是一个二维的离散信号&#xff0c;对数字图像做卷积操作其实就是利用卷积核&#xff08;卷积模板&#xff09;在图像上滑动&#xff0c;将图像点上的像素灰度值与对应的卷积核上的数值相乘&#xff0c;然后将所有相乘后的值相加作为卷积核中间像素对应的图像…

matlab自带的插值函数interp1的四种插值方法

x0:2*pi; ysin(x); xx0:0.5:2*pi;%interp1对sin函数进行分段线性插值&#xff0c;调用interp1的时候&#xff0c;默认的是分段线性插值 y1interp1(x,y,xx); figure plot(x,y,o,xx,y1,r) title(分段线性插值)%临近插值 y2interp1(x,y,xx,nearest); figure plot(x,y,o,xx,y2,r); …

拉格朗日插值法(Lagrange)

拉格朗日插值法是基于基函数的插值方法&#xff0c;插值多项式可以表示为&#xff1a; 其中称为 i 次基函数 Matlab中拉格朗日插值法函数为:Language 功能&#xff1a;求已知点数据点的拉格朗日多项式 调用格式&#xff1a;fLagrange(x,y) 或者 f ’Lagrange(x,y,x0) 其中&a…