一、git 全局配置

全局配置:

设置编码
git config --global gui.encoding utf-8
git config --global i18n.commitencoding utf-8
git config --global i18n.logoutputencoding utf-8

指定git或gitlab的用户名与邮箱
bogon:~ yuanjicai$ git config --global user.name meteor
bogon:~ yuanjicai$ git config --global user.email meteor@163.com
bogon:~ yuanjicai$ git config --global color.ui true

换行设置
git config --global core.autocrlf input  #提交时转换为LF,检出时不转换
git config --global core.safecrlf warn   #提交包含混合换行符的文件时给出警告

查看配置:

bogon:~ yuanjicai$ git config --list | tail -3
user.name=meteor
user.email=meteor@163.com
color.ui=true
bogon:~ yuanjicai$

实质上是将配置写入了~/.gitconfig文件(当然直接修改该文件也可以达到配置的目的)

bogon:~ yuanjicai$ ls .gitconfig
.gitconfig
bogon:~ yuanjicai$ cat .gitconfig
[user]
name = meteor
email = meteor@163.com
[color]
ui = true
bogon:~ yuanjicai$

二、git新建项目及初始化

法一、新建立项目:

bogon:~ yuanjicai$ mkdir -p github/project
bogon:~ yuanjicai$ cd github/project/
bogon:project yuanjicai$ git init    #初始化仓库
Initialized empty Git repository in /Users/yuanjicai/github/project/.git/
bogon:project yuanjicai$ ls -a
....git
bogon:project yuanjicai$ cd  .git
bogon:.git yuanjicai$ ls
HEAD config hooks objects
branches description inforefs
bogon:.git yuanjicai$                 #git 保存分支的地方

方法二:

bogon:github yuanjicai$ pwd
/Users/yuanjicai/github
bogon:github yuanjicai$ ls
project
bogon:github yuanjicai$ git clone https://github.com/kennethreitz/requests.git
Cloning into 'requests'...
remote: Counting objects: 17906, done.
remote: Compressing objects: 100% (35/35), done.
remote: Total 17906 (delta 11), reused 0 (delta 0), pack-reused 17871
Receiving objects: 100% (17906/17906), 4.79 MiB | 643.00 KiB/s, done.
Resolving deltas: 100% (11665/11665), done.
Checking connectivity... done.
bogon:github yuanjicai$ ls
projectrequests
bogon:github yuanjicai$ ls requests/
AUTHORS.rstMakefilerequests
CONTRIBUTING.mdNOTICErequirements-to-freeze.txt
HISTORY.rstREADME.rstrequirements.txt
LICENSEdocssetup.py
MANIFEST.inexttests
bogon:github yuanjicai$ ls requests/.git
HEADconfighooksinfoobjectsrefs
branchesdescriptionindexlogspacked-refs
bogon:github yuanjicai$

三、建立文件并提交

bogon:github yuanjicai$ cd project/
bogon:project yuanjicai$ ls .git/
COMMIT_EDITMSGORIG_HEADconfighooksinfoobjects
HEADbranchesdescriptionindexlogsrefs
bogon:project yuanjicai$ ls
bogon:project yuanjicai$ vim test1.py
bogon:project yuanjicai$ python test1.py
hello world
bogon:project yuanjicai$ vim test2.py
bogon:project yuanjicai$ python test2.py
hello YeeCall
bogon:project yuanjicai$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)
test1.py
test2.py
nothing added to commit but untracked files present (use "git add" to track)
bogon:project yuanjicai$ git add test1.py  test2.py
bogon:project yuanjicai$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
new file:   test1.py
new file:   test2.py
bogon:project yuanjicai$ git commit -m "init commit"
[master 547a6b0] init commit
 2 files changed, 2 insertions(+)
 create mode 100644 test1.py
 create mode 100644 test2.py
bogon:project yuanjicai$ git status
On branch master
nothing to commit, working tree clean
bogon:project yuanjicai$

wKiom1e0Bi-hNEgsAACt3yC6ly8004.png

四、git status

bogon:project yuanjicai$ vim test2.py
bogon:project yuanjicai$ python test2.py
hello YeeCall
hello git
bogon:project yuanjicai$ 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:   test2.py
no changes added to commit (use "git add" and/or "git commit -a")
bogon:project yuanjicai$ echo '*~' > .gitignore
bogon:project yuanjicai$ git add .gitignore
bogon:project yuanjicai$ git status -s
A  .gitignore
 M test2.py                #第二位的M表示working directory有修改
bogon:project yuanjicai$ git add .gitignore
bogon:project yuanjicai$ git add test2.py
bogon:project yuanjicai$ git status -s
A  .gitignore
M  test2.py
bogon:project yuanjicai$ vim test2.py
bogon:project yuanjicai$ python test2.py
hello YeeCall
hello git
hello maven
bogon:project yuanjicai$ git status -s
A  .gitignore
MM test2.py        #第一个M表示staging有修改,第二个M表示working directory有修改

五、git diff 

bogon:project yuanjicai$ vim test1.py
bogon:project yuanjicai$ python test1.py
hello world
hello op
bogon:project yuanjicai$ git status -s
 M test1.py
bogon:project yuanjicai$ git diff        #默认git diff 只检查第二个标志位(即检查working directory与staging的数据是否一致)
diff --git a/test1.py b/test1.py
index a968078..6e43c62 100644
--- a/test1.py
+++ b/test1.py                    #表示本行为新添加的内容
@@ -1 +1,2 @@
 print 'hello world'
+print 'hello op'
bogon:project yuanjicai$ git add test1.py
bogon:project yuanjicai$ git status -s
M  test1.py
bogon:project yuanjicai$ git diff
bogon:project yuanjicai$ git diff --staged   #表示检查stage与history中的数据是否一致
diff --git a/test1.py b/test1.py
index a968078..6e43c62 100644
--- a/test1.py
+++ b/test1.py
@@ -1 +1,2 @@
 print 'hello world'
+print 'hello op'
bogon:project yuanjicai$ git diff HEAD      #检查working directory与history是否一致,HEAD指针就指向最后一次提交的内容
diff --git a/test1.py b/test1.py
index a968078..6e43c62 100644
--- a/test1.py
+++ b/test1.py
@@ -1 +1,2 @@
 print 'hello world'
+print 'hello op'
bogon:project yuanjicai$
bogon:project yuanjicai$ git diff --stat        #输出简要信息
bogon:project yuanjicai$ git diff --staged --stat
 test1.py | 1 +
 1 file changed, 1 insertion(+)
bogon:project yuanjicai$ git diff HEAD --stat
 test1.py | 1 +
 1 file changed, 1 insertion(+)
bogon:project yuanjicai$
bogon:project yuanjicai$ git commit -m 'second commit'  #从stage中将数据提交致history中
[master b89e642] second commit
 1 file changed, 1 insertion(+)
bogon:project yuanjicai$

六、下载

bogon:project yuanjicai$ vim test1.py
bogon:project yuanjicai$ cat test1.py
print 'hello world'
print 'hello op.....'
bogon:project yuanjicai$ git diff --stat
 test1.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
bogon:project yuanjicai$ git add test1.py
bogon:project yuanjicai$ git diff --stat
bogon:project yuanjicai$ git diff --staged --stat   #比较stage与history中的数据是否一致
 test1.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
bogon:project yuanjicai$ git reset test1.py       #下载历史history中的最后一个版本致stage中
Unstaged changes after reset:
Mtest1.py
bogon:project yuanjicai$ git diff --staged --stat
bogon:project yuanjicai$ git diff HEAD --stat      #比较working directory与history中的数据是否一致
 test1.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
bogon:project yuanjicai$ git checkout test1.py        #下载stage中的数据致working directory
bogon:project yuanjicai$ git diff HEAD --stat
bogon:project yuanjicai$ echo "xxxxx" >> test1.py
bogon:project yuanjicai$ git diff HEAD --stat       #发现stage与working directory已经不一致
 test1.py | 1 +
 1 file changed, 1 insertion(+)
bogon:project yuanjicai$ git checkout HEAD test1.py    #从history中直接下载历史版本到working directory 
bogon:project yuanjicai$ git diff HEAD --stat
bogon:project yuanjicai$
bogon:project yuanjicai$ vim test1.py
bogon:project yuanjicai$ cat test1.py
print 'hello world'
print 'hello op !!'
bogon:project yuanjicai$ git commit -am 'third commit'  #直接由working directory提交到history
[master bcc815a] third commit
 1 file changed, 1 insertion(+), 1 deletion(-)
bogon:project yuanjicai$ git diff --staged

wKiom1e0GvKxaBoAAADu6yRXpLk057.png

七、删除数据

bogon:project yuanjicai$ echo "newfile" > test3.txt    #新建立文件test3.txt
bogon:project yuanjicai$ git add test3.txt添加并提交
bogon:project yuanjicai$ git commit -m "add test3.txt"
[master 5626d79] add test3.txt
 1 file changed, 1 insertion(+)
 create mode 100644 test3.txt
bogon:project yuanjicai$ git rm test3.txt        #删除test3.txt
rm 'test3.txt'
bogon:project yuanjicai$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
deleted:    test3.txt
bogon:project yuanjicai$ git status -s
D  test3.txt
bogon:project yuanjicai$ git commit -m "delete test3.txt"  #提交删除
[master 6e928e5] delete test3.txt
 1 file changed, 1 deletion(-)
 delete mode 100644 test3.txt
bogon:project yuanjicai$ git status -s
bogon:project yuanjicai$
bogon:project yuanjicai$
bogon:project yuanjicai$ git rm --cached test2.py    #仅删除staging中的文件
rm 'test2.py'
bogon:project yuanjicai$ git status -s
D  test2.py
?? test2.py
bogon:project yuanjicai$ git reset test2.py        #再次从history中下载最后一个版本的文件
bogon:project yuanjicai$ git status -s
bogon:project yuanjicai$
bogon:project yuanjicai$ git rm --cache test2.py     #删除staging中的文件,将 working directory中的数据改名,并再次添加、提交
rm 'test2.py'
bogon:project yuanjicai$ mv test2.py test4.py
bogon:project yuanjicai$ git add test4.py
bogon:project yuanjicai$ git status -s
R  test2.py -> test4.py
bogon:project yuanjicai$ git commit -m 'rename test2.py to test4.py'
[master 9845bda] rename test2.py to test4.py
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename test2.py => test4.py (100%)
bogon:project yuanjicai$ git status -s
bogon:project yuanjicai$

八、stash暂存

bogon:project yuanjicai$ vim test1.py
bogon:project yuanjicai$ cat test1.py    #修改源文件
print 'hello world'
print 'hello op !!'
print 'xxxxxxxxxxx'
print 'yyyyyyyyyyy'
bogon:project yuanjicai$ git stash    #暂存当前正在进行的工作
Saved working directory and index state WIP on master: 9845bda rename test2.py to test4.py
HEAD is now at 9845bda rename test2.py to test4.py
bogon:project yuanjicai$ git status
On branch master
nothing to commit, working tree clean
bogon:project yuanjicai$ cat test1.py    #查看文件的内容(已经是之前没有修改前的内容)
print 'hello world'
print 'hello op !!'
bogon:project yuanjicai$ vim test1.py
bogon:project yuanjicai$ cat test1.py    #编辑源代码文件(加了两个感叹号)
print 'hello world!!'
print 'hello op !!'
bogon:project yuanjicai$ git commit -am 'quick update'    #提交修改后的代码
[master 23a727c] quick update
 1 file changed, 1 insertion(+), 1 deletion(-)
bogon:project yuanjicai$ git stash list    #查看之前的暂存区
stash@{0}: WIP on master: 9845bda rename test2.py to test4.py
stash@{1}: filter-branch: rewrite
stash@{2}: WIP on master: 7f68a1a update
bogon:project yuanjicai$ git stash pop    #取出上次的暂存
Auto-merging test1.py
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:   test1.py
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (33fb283741bb2747c55a9ddee45118f84b65c498)
bogon:project yuanjicai$ cat test1.py    #查看文件的内容(已经又回到了暂存时状态)
print 'hello world!!'
print 'hello op !!'
print 'xxxxxxxxxxx'
print 'yyyyyyyyyyy'
bogon:project yuanjicai$

九、history 详解

git commit 之后就会提交到history area。然后history area 中存储 本次提交 commit  history 。每次的commit history 又由 parent tree组成。而每个 parent 都会指向它前一个commit history 。最后一次提交的commit history被标记为 HEAD。前一次的被标记为 HEAD~ ,再前一次的被标记为HEAD~2 …  依次类推。

wKioL1e0KzSBW99lAAEvq68CiMs911.png

每个tree 又由多个文件或子目录组成,每个子目录下又可以由多个文件或子目录组成。

输入git log 可以看到之前提交的记录,以及每次提交时,每个commit historyhash码。

git  cat-file  -t  HEAD     可以查看最后一次commit history 的指向类型

git cat-file  -p  HEAD            可以查看最后一次commit history中的内容,包括 tree parenthash 

git cat-file  -t    Treehash        说明: -t 查看类型    -p 查看内容 

可以查看到每个文件或目录也对应一个hash 。其中blob表示二进制

bogon:project yuanjicai$ git log --oneline
23a727c quick update
9845bda rename test2.py to test4.py
6e928e5 delete test3.txt
5626d79 add test3.txt
bcc815a third commit
b89e642 second commit
f492923 first commit
547a6b0 init commit
bogon:project yuanjicai$ git cat-file -t 23a727c
commit
bogon:project yuanjicai$ git cat-file -p 23a727c
tree bfbf9746b6279366e43117c3a94ff38692d1b60f
parent 9845bda97fdaca363b07f703a88259976a58261c
author meteor <meteor@163.com> 1471422986 +0800
committer meteor <meteor@163.com> 1471422986 +0800
quick update
bogon:project yuanjicai$ git cat-file -t HEAD        #等同于git cat-file -t 23a727c命令
commit
bogon:project yuanjicai$ git cat-file -p HEAD        #等同于git cat-file -p 23a727c命令
tree bfbf9746b6279366e43117c3a94ff38692d1b60f
parent 9845bda97fdaca363b07f703a88259976a58261c
author meteor <meteor@163.com> 1471422986 +0800
committer meteor <meteor@163.com> 1471422986 +0800
quick update
bogon:project yuanjicai$ git cat-file -p HEAD~        #等同于git cat-file -p 9845bda
tree bee185fc174697cf400998818e4ca099ca00e275
parent 6e928e51ab05ad2c60b0d51cfd6b7d0cae783ec3
author meteor <meteor@163.com> 1471422174 +0800
committer meteor <meteor@163.com> 1471422174 +0800
rename test2.py to test4.py
bogon:project yuanjicai$ git cat-file -p bee185f
100644 blob b25c15b81fae06e1c55946ac6270bfdb293870e8.gitignore
100644 blob b351508c3cadddc4ea579967d1c3177364fd5a48test1.py
100644 blob 5de2b690c836079832d879f9d2902ac58043f5b9test4.py
bogon:project yuanjicai$
bogon:project yuanjicai$ git cat-file -p b3515
print 'hello world'
print 'hello op !!'
bogon:project yuanjicai$ git show -p b3515
print 'hello world'
print 'hello op !!'
bogon:project yuanjicai$

十、tree-ish

bogon:project yuanjicai$ ls -A
.git.gitignoretest1.pytest4.py
bogon:project yuanjicai$ cd .git
bogon:.git yuanjicai$ ls
COMMIT_EDITMSGORIG_HEADconfighooksinfoobjects
HEADbranchesdescriptionindexlogsrefs
bogon:.git yuanjicai$ cat HEAD
ref: refs/heads/master说明 HEAD指向master分支
bogon:.git yuanjicai$ cd refs/
bogon:refs yuanjicai$ tree
.
|____heads
| |____mastermaster实质上是一个分支(branch)
|____original
| |____refs
| | |____heads
| | | |____master
| | |____stash
|____stash
|____tags
bogon:refs yuanjicai$ cat heads/master       #master又指向23a72
23a727c534d620339d3382d8284859f6a75f3194
bogon:refs yuanjicai$ git log --oneline | head -2 #hash23a727就是最后一次的提交
23a727c quick update
9845bda rename test2.py to test4.py
bogon:refs yuanjicai$ git cat-file -t 23a727   #查看hash 23a727的类型是commit history
commit
bogon:refs yuanjicai$
#从上述可以看到 HEAD实质上是指几最后一个commit history的master branch ,而master branch再指向本次的commit history(另外 master~ 等同于HEAD~)
bogon:refs yuanjicai$ git rev-parse HEAD
23a727c534d620339d3382d8284859f6a75f3194
bogon:refs yuanjicai$ git rev-parse master
23a727c534d620339d3382d8284859f6a75f3194
bogon:refs yuanjicai$
bogon:refs yuanjicai$ git rev-parse HEAD~       #说明:git rev-parse master~  等同 git rev-parse HEAD~
9845bda97fdaca363b07f703a88259976a58261c
bogon:refs yuanjicai$ git rev-parse master~
9845bda97fdaca363b07f703a88259976a58261c
bogon:refs yuanjicai$
bogon:refs yuanjicai$ git rev-parse HEAD~^{tree}   #说明:查看倒数第二次commit history中的tree的hash值
bee185fc174697cf400998818e4ca099ca00e275
bogon:refs yuanjicai$ git rev-parse HEAD~:test1.py
b351508c3cadddc4ea579967d1c3177364fd5a48
bogon:refs yuanjicai$ git cat-file -p b3515
print 'hello world'
print 'hello op !!'
bogon:refs yuanjicai$ git show HEAD~:test1.py
print 'hello world'
print 'hello op !!'
bogon:refs yuanjicai$

十一、branch分支

bogon:project yuanjicai$ 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:   test1.py
no changes added to commit (use "git add" and/or "git commit -a")
bogon:project yuanjicai$ cat test1.py
print 'hello world!!'
print 'hello op !!'
print 'xxxxxxxxxxx'
print 'yyyyyyyyyyy'
bogon:project yuanjicai$ git commit -am "stash commit"
[master 26415ad] stash commit
 1 file changed, 2 insertions(+)
bogon:project yuanjicai$ git branch            #查看分支 (*表示当前的 branch)
* master
bogon:project yuanjicai$ git branch newidea         #创建分支
bogon:project yuanjicai$ git branch            #再次查看分支
* master
  newidea
bogon:project yuanjicai$ git checkout newidea       #切换新的分支
Switched to branch 'newidea'
bogon:project yuanjicai$ cat .git/HEAD           #查看当前HEAD指向newidea分支
ref: refs/heads/newidea
bogon:project yuanjicai$ ls .git/refs/heads/        #查看现有分支的存储情况
masternewidea
bogon:project yuanjicai$ cat .git/refs/heads/*        #查看两个分支都指向同一个commit history
26415adb026d04fd2e375adedd6afcad8c0322ea
26415adb026d04fd2e375adedd6afcad8c0322ea
bogon:project yuanjicai$ git checkout master        #现次切换回master分支 
Switched to branch 'master'
bogon:project yuanjicai$ git branch -d newidea        #删除指定分支
Deleted branch newidea (was 26415ad).
bogon:project yuanjicai$ git branch              #再次查看分支
* master
bogon:project yuanjicai$
bogon:project yuanjicai$ git checkout -b newcode       #参数-b 作用:检查如果没有branch则新建立
Switched to a new branch 'newcode'
bogon:project yuanjicai$ ls
test1.pytest4.py
bogon:project yuanjicai$ vim test1.py
bogon:project yuanjicai$ cat test1.py
print 'hello world!!'
print 'hello op !!'
print 'xxxxxxxxxxx'
print 'yyyyyyyyyyy'
print 'zzzzzzzzzzz'
bogon:project yuanjicai$ git commit -am 'newcode update'
[newcode 6c10be1] newcode update
 1 file changed, 1 insertion(+)
bogon:project yuanjicai$ git checkout master
Switched to branch 'master'
bogon:project yuanjicai$ git branch
* master
  newcode
bogon:project yuanjicai$ git branch -d newcode       #此时删除 新分支时无法删除 
error: The branch 'newcode' is not fully merged.
If you are sure you want to delete it, run 'git branch -D newcode'.
bogon:project yuanjicai$ git merge newcode         #合并分支
Updating 26415ad..6c10be1
Fast-forward                             #合并类型为Fast-forward
 test1.py | 1 +
 1 file changed, 1 insertion(+)
bogon:project yuanjicai$
bogon:project yuanjicai$ git branch -d newcode        #合并分支后就可以删除newcode分支了
Deleted branch newcode (was 6c10be1).
bogon:project yuanjicai$ git branch
* master
bogon:project yuanjicai$
bogon:project yuanjicai$ git checkout -b bugfix
Switched to a new branch 'bugfix'
bogon:project yuanjicai$ vim test1.py
bogon:project yuanjicai$ git commit -am 'bug fix1'
[bugfix eba1606] bug fix1
 1 file changed, 1 insertion(+), 1 deletion(-)
bogon:project yuanjicai$ vim test1.py
bogon:project yuanjicai$ git commit -am 'bug fix2'
print 'hello world!!'
[bugfix 48a5fd6] bug fix2
 1 file changed, 1 insertion(+), 1 deletion(-)
bogon:project yuanjicai$ git log --oneline | head -3
48a5fd6 bug fix2
eba1606 bug fix1
6c10be1 newcode update
bogon:project yuanjicai$ git checkout master
Switched to branch 'master'
bogon:project yuanjicai$ vim test1.py
bogon:project yuanjicai$ git commit -am 'last update'
[master 329577a] last update
 1 file changed, 1 insertion(+), 1 deletion(-)
bogon:project yuanjicai$ git log --oneline | head -2
329577a last update
6c10be1 newcode update
bogon:project yuanjicai$ git merge bugfix                #合并分支
Auto-merging test1.py
CONFLICT (content): Merge conflict in test1.py              #冲突内容:合并冲突在 test1.py文件中
Automatic merge failed; fix conflicts and then commit the result.  #自动合并失败;修改冲突然后提交修改后的结果
然后查看test.py源文件内容,如下
<<<<<<<< HEAD
         当前分支的代码
===============
         被合并分支的代码
>>>>>>>>>>>>>>>

这种冲突首先先分析两部分代码是实现相同功能而写的重复的代码,还是各自实现的不同的功能的代码。如果是重复代码:两个二选一删除一个,然后再把这些冲突标示符删除即可;如果不是重复代码,两个都需要保留,只需要把冲突符号删除即可。工程编译通过之后可以重新提交。如下所示:

bogon:project yuanjicai$ vim test1.py          #删除重复代码,保留需要的部分
bogon:project yuanjicai$ git add test1.py        #重新添加
bogon:project yuanjicai$ git commit -m 'merge update' #重新提交
[master 2b677c0] merge update
bogon:project yuanjicai$ git branch -d bugfix    #删除无用的分支
Deleted branch bugfix (was 48a5fd6).
bogon:project yuanjicai$ git branch          #查看当前分支
* master
bogon:project yuanjicai$