Git学习心得和Git教程整理

2015/12/28 Git

总结

Git简明工作原理

当使用git commit新建一个提交对象前,Git会先计算每一个子目录(本例中就是项目根目录)的校验和,然后在Git仓库中将这些目录保存为树(tree)对象。之后Git创建的提交对象,除了包含相关提交信息以外,还包含着指向这个树对象(项目根目录)的指针,如此它就可以在将来需要的时候,重现此次快照的内容了。

title


工作区和暂存区

工作区就是你在电脑里能看到git本地库所在的workspace目录

版本库工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库

暂存区Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区

title

暂存操作:

title

提交操作:

title


基本操作

初始化仓库

git init命令把这个目录变成Git可以管理的仓库

$ git init
Initialized empty Git repository in /Users/michael/learngit/.git/

添加文件

git add告诉Git,把文件添加到暂存区

git add readme.txt

git commit告诉Git,把文件提交到仓库

	$ git commit -m "wrote a readme file"
	[master (root-commit) cb926e7] wrote a readme file
	 1 file changed, 2 insertions(+)
	 create mode 100644 readme.txt

查看文件状态

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:   readme.txt
	#
	no changes added to commit (use "git add" and/or "git commit -a")

git diff对比文件变更

$ git diff readme.txt
diff --git a/readme.txt b/readme.txt
index 46d49bf..9247db6 100644
--- a/readme.txt
+++ b/readme.txt
@@ -1,2 +1,2 @@
-Git is a version control system.
+Git is a distributed version control system.
	Git is free software.

撤销修改

checkout -- file可以丢弃工作区的修改

git checkout -- file命令中的--很重要,没有--,就变成了“切换到另一个分支”的命令,测试不加也可以成功执行放弃更改操作,但是工作区中没有与分支名相同的文件(用github for windows 的powershell测试)

	$ git checkout -- readme.txt

版本回退

git log可以查看提交历史

	$ git log
	commit 3628164fb26d48395383f8f31179f24e0882e1e0
	Author: Michael Liao <askxuefeng@gmail.com>
	Date:   Tue Aug 20 15:11:49 2013 +0800

	    append GPL

	commit ea34578d5496d7dd233c827ed32a8cd576c5ee85
	Author: Michael Liao <askxuefeng@gmail.com>
	Date:   Tue Aug 20 14:53:12 2013 +0800

	    add distributed

	commit cb926e7ea50ad11b8f9e909c05226233bf755030
	Author: Michael Liao <askxuefeng@gmail.com>
	Date:   Mon Aug 19 17:51:55 2013 +0800

	    wrote a readme file
	$ git log --pretty=oneline
	3628164fb26d48395383f8f31179f24e0882e1e0 append GPL
	ea34578d5496d7dd233c827ed32a8cd576c5ee85 add distributed
	cb926e7ea50ad11b8f9e909c05226233bf755030 wrote a readme file

git show 查看commit的变更内容

git show 718f6272fecd17313b35cb5b343fc6e7b0e98a98

git reset在版本的历史之间切换

	$ git reset --hard HEAD^
	HEAD is now at ea34578 add distributed
	$ git reset --hard 3628164
	HEAD is now at 3628164 append GPL

HEAD指向的就是当前分支(请看分支部分)

HEAD表示当前版本,上一个版本就是HEAD^,上上一个版本就是HEAD^^,当然往上100个版本写100个^比较容易数不过来,所以写成HEAD~100

回退前:title

回退后:title

git reflog查看命令历史

	$ git reflog
	ea34578 HEAD@{0}: reset: moving to HEAD^
	3628164 HEAD@{1}: commit: append GPL
	ea34578 HEAD@{2}: commit: add distributed
	cb926e7 HEAD@{3}: commit (initial): wrote a readme file

场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout --file

场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,第一步用命令git reset HEAD file,就回到了场景1,第二步按场景1操作。

场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退,使用命令git reset HEAD commit_id回退版本,这个操作也回退到场景1,不过前提是没有推送到远程库。

删除文件

git rm用于删除一个文件

	$ git rm test.txt
	rm 'test.txt'
	$ git commit -m "remove test.txt"
	[master d17efd8] remove test.txt
	 1 file changed, 1 deletion(-)
	 delete mode 100644 test.txt

先执行rm命令只能删除当前文件系统的文件,commmit后会删除版本库中的文件。

如果先执行git rm命令,则会删除版本库中的文件,本地会出现一个未追踪的更改(删除的文件)。

这里的删除都是逻辑删除,可以通过Git历史还原


分支

HEAD和分支图解

HEAD指向示意

title

分支切换示意

title

创建分支

git checkout命令加上-b参数表示创建并切换

	$ git checkout -b dev
	Switched to a new branch 'dev'

相当于git branch创建分支后git checkout切换到新分支

	$ git branch dev
	$ git checkout dev
	Switched to branch 'dev'

git branch命令查看当前分支

	$ git branch
	* dev
	  master

合并分支

git merge命令用于合并指定分支到当前分支

	$ git merge dev
	Updating d17efd8..fec145a
	Fast-forward
	 readme.txt |    1 +
	 1 file changed, 1 insertion(+)

合并分支时,加上--no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。

删除分支

git branch -d命令用于删除分支

	$ git branch -d dev
	Deleted branch dev (was fec145a).

关联远程分支

git branch --set-upstream-to origin/master local-branch-name

如果删除一个没有被合并的分支,git将会提示

	$ git branch -d feature-vulcan
	error: The branch 'feature-vulcan' is not fully merged.
	If you are sure you want to delete it, run 'git branch -D feature-vulcan'.

这时候,使用git branch -D强行删除(注意,这里会丢失所有为合并的改动)

	$ git branch -D feature-vulcan
	Deleted branch feature-vulcan (was 756d4af).

分支策略

在实际开发中,我们通常这样进行分支管理:

首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;

那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;

你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。

所以,团队合作的分支看起来就像这样:

title


解决冲突

冲突形成

master分支和feature1分支各自都分别有新的提交

title

修改相同文件位置情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突

	$ git merge feature1
	Auto-merging readme.txt
	CONFLICT (content): Merge conflict in readme.txt
	Automatic merge failed; fix conflicts and then commit the result.

查看冲突并解决

git status也可以告诉我们冲突的文件

	$ git status
	# On branch master
	# Your branch is ahead of 'origin/master' by 2 commits.
	#
	# Unmerged paths:
	#   (use "git add/rm <file>..." as appropriate to mark resolution)
	#
	#       both modified:      readme.txt
	#
	no changes added to commit (use "git add" and/or "git commit -a")

Git用<<<<<<<=======>>>>>>>标记出不同分支的内容

	Git is a distributed version control system.
	Git is free software distributed under the GPL.
	Git has a mutable index called stage.
	Git tracks changes of files.
	<<<<<<< HEAD
	Creating a new branch is quick & simple.
	=======
	Creating a new branch is quick AND simple.
	>>>>>>> feature1

结局后提交文件

	$ git add readme.txt
	$ git commit -m "conflict fixed"
	[master 59bc1cb] conflict fixed

合并后的示意图

title

git log --graph --pretty=oneline也可以看到分支的合并情况

	$ git log --graph --pretty=oneline --abbrev-commit
	*   59bc1cb conflict fixed
	|\
	| * 75a857c AND simple
	* | 400b400 & simple
	|/
	* fec145a branch test
	...

储藏

为什么使用储藏

经常有这样的事情发生,当你正在进行项目中某一部分的工作,里面的东西处于一个比较杂乱的状态,而你 想转到其他分支上进行一些工作。问题是,你不想提交进行了一半的工作,否则以后你无法回到这个工作点。

	$ git status
	# On branch dev
	# Changes to be committed:
	#   (use "git reset HEAD <file>..." to unstage)
	#
	#       new file:   hello.py
	#
	# 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:   readme.txt
	#

存储现场

git stash把当前工作现场“储藏”起来

	$ git stash
	Saved working directory and index state WIP on dev: 6224937 add merge
	HEAD is now at 6224937 add merge

现在,用git status查看工作区,就是干净的(除非有没有被Git管理的文件,存储前需要先add文件到存储区,存储实际是吧存储区编号进栈),因此可以放心地创建分支来修复bug(一般的,存储后即在现有分支上创建一个干净的新分支开始工作)。

还原现场

git stash list命令查看被存储的存储区

	$ git stash list
	stash@{0}: WIP on dev: 6224937 add merge

git stash pop恢复的同时把stash内容除

	$ git stash pop
	# On branch dev
	# Changes to be committed:
	#   (use "git reset HEAD <file>..." to unstage)
	#
	#       new file:   hello.py
	#
	# 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:   readme.txt
	#
	Dropped refs/stash@{0} (f624f8e5f082f2df2bed8a4e09c12fd2943bdd40)

相当于用git stash apply恢复,恢复后,再用git stash drop来删除stash内容

你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:

$ git stash apply stash@{0}

远程仓库

配置全局用户信息

git config --global user.name "username"
git config --global user.email "email"
ssh-keygen -t rsa -C "xp@mail.com"

链接远程仓库

git clone命令将远程仓库克隆出新的仓库

$ git clone git@github.com:michaelliao/gitskills.git
Cloning into 'gitskills'...
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (3/3), done.

$ cd gitskills
$ ls
README.md

Git支持多种协议,包括https,但通过ssh支持的原生git协议速度最快,git协议是ssh协议省去了加密和身份认证的协议,http协议相对最慢。

git remote add命令将已有的本地仓库与远程仓库关联

git init
git add Readme.md
git commit -m "init"
git remote add origin git@github.com:michaelliao/learngit.git
git push -u origin master

远程库的名字就是origin,这是Git默认的叫法,也可以改成别的

查看远程仓库信息

git remote查看远程库的信息

	$ git remote -v
	origin  git@github.com:michaelliao/learngit.git (fetch)
	origin  git@github.com:michaelliao/learngit.git (push)

推送分支

git push命令把本地库推送到远程

	$ git push -u origin master
	Counting objects: 19, done.
	Delta compression using up to 4 threads.
	Compressing objects: 100% (19/19), done.
	Writing objects: 100% (19/19), 13.73 KiB, done.
	Total 23 (delta 6), reused 0 (delta 0)
	To git@github.com:michaelliao/learngit.git
	 * [new branch]      master -> master
	 *
	Branch master set up to track remote branch master from origin.

远程如果库是空的,第一次推送master分支时,加上了-u参数,Git不但会把本地的master分支内容推送的远程新的master分支,还会把本地的master分支和远程的master分支关联起来,在以后的推送或者拉取时就可以简化命令。

只要本地作了提交,就可以通过命令:

	$ git push origin master

把本地master分支的最新修改推送至GitHub

抓取分支

git pull把最新的提交从origin抓下来

$ git pull
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From github.com:michaelliao/learngit
fc38031..291bea8  dev        -> origin/dev
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details

git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

git branch --set-upstream dev origin/<branch>

git pull失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接

git branch --set-upstream设置分支链接

$ git branch --set-upstream dev origin/dev
Branch dev set up to track remote branch dev from origin.

git pull成功

$ git pull
Auto-merging hello.py
CONFLICT (content): Merge conflict in hello.py
Automatic merge failed; fix conflicts and then commit the result.

因此,多人协作的提交流程通常是这样:

首先,可以试图用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。

# 先init commit然后pull失败问题
git pull --allow-unrelated-histories origin master

标签

创建标签

git tag <name>用于新建一个标签,默认为HEAD,也可以指定一个commit id

$ git tag -a v0.1 -m "version 0.1 released" 3628164

-a指定标签名,-m指定说明文字,或者简单的使用git tag v1.0对HEAD打一个标签

git tag查看标签

	$ git tag
	v0.9
	v1.0

注意,标签不是按时间顺序列出,而是按字母排序的。可以用git show <tagname>查看标签信息

	$ git show v0.9
	commit 622493706ab447b6bb37e4e2a2f276a20fed2ab4
	Author: Michael Liao <askxuefeng@gmail.com>
	Date:   Thu Aug 22 11:22:08 2013 +0800

	    add merge
	...

推送标签

git push origin <tagname>推送标签到远程

	$ 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推送全部未推送过的本地标签

	$ 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命令删除标签

	$ git tag -d v0.1
	Deleted tag 'v0.1' (was e078af9)

git push origin :refs/tags/<tagname>删除远程标签

	$ git push origin :refs/tags/v0.9
	To git@github.com:michaelliao/learngit.git
	 - [deleted]         v0.9

教程

这个博客的git教程还是不错的,上个面的总结来自这里

http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000

Pro Git教程

Pro Git中文github地址

https://github.com/progit/progit/tree/master/zh

Pro Git 2中文github地址

https://github.com/progit/progit/tree/master/zh

或者去我的网盘下载pdf教程 提取密码:wn45

http://pan.baidu.com/s/1pJVoaAR

Search

    Post Directory