git 学习笔记

三个区的概念:

working tree指工作区
index指暂存区
HEAD指最近的版本库,即最近一次commit之后的版本

diff操作

git diff:是查看working tree与index file的差别的。
git diff --cached:是查看index file与commit的差别的。
git diff HEAD:是查看working tree和commit的差别的。(你一定没有忘记,HEAD代表的是最近的一次commit的信息)

reset 操作

git reset --mixed:此为默认方式,不带任何参数的git reset,即时这种方式,它回退到某个版本,只保留源码,head和index信息都会被退回
git reset --soft:回退到某个版本,只回退了head的信息,不会恢复到index file一级。如果还要提交,直接commit即可
git reset --hard:彻底回退到某个版本,本地的源码也会变为上一个版本的内容,此命令 慎用!

关于branch

branch不只是针对版本区,如果切换branch,工作区和暂存区,都会发生变化的。所以如果有工作没有commit,则不能执行rebase、checkout等操作。如果一定要执行,则要使用git stash命令把未commit的工作暂时”搁置“,等完成了相关执行,再用git stash pop命令回来继续工作。

如下,在master分支上有过一次修改,未add到index上,在执行rebase和checkout时,都提醒失败,要先stash:

lxl_lib1@DESKTOP-RGUV9II MINGW64 /f/Programming Learning/git learning (master)
$ 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:   git learning.txt

no changes added to commit (use "git add" and/or "git commit -a")

lxl_lib1@DESKTOP-RGUV9II MINGW64 /f/Programming Learning/git learning (master)
$ git checkout dev_testrebase
error: Your local changes to the following files would be overwritten by checkout:
        git learning.txt
Please commit your changes or stash them before you switch branches.
Aborting

lxl_lib1@DESKTOP-RGUV9II MINGW64 /f/Programming Learning/git learning (master)
$ git rebase dev_testrebase
Cannot rebase: You have unstaged changes.
Please commit or stash them.

 执行add操作添加到index上后,未commit到heard,也是一样的提示失败:

 1 $ git add "git learning.txt"
 2 
 3 lxl_lib1@DESKTOP-RGUV9II MINGW64 /f/Programming Learning/git learning (master)
 4 $ git status
 5 On branch master
 6 Changes to be committed:
 7   (use "git reset HEAD <file>..." to unstage)
 8 
 9         modified:   git learning.txt
10 
11 
12 lxl_lib1@DESKTOP-RGUV9II MINGW64 /f/Programming Learning/git learning (master)
13 $ git rebase dev_testrebase
14 Cannot rebase: Your index contains uncommitted changes.
15 Please commit or stash them.

 如果不想保存当前分支所做的未commit的修改,想强制切换到别的分支,可以使用checkout -f anotherbranch。因为chechout会把当前的工作区、index区和版本区都换成anotherbranch的(其实是清空了工作区和index区,一个分支checkout出来时总是干净的),所以所有未commit的内容都没了。再切换加来,运行git status,发现工作区和index区什么也没有了:

 1 lxl_lib1@DESKTOP-RGUV9II MINGW64 /f/Programming Learning/git learning (master)
 2 $ git checkout -f dev_testrebase
 3 Switched to branch 'dev_testrebase'
 4 
 5 lxl_lib1@DESKTOP-RGUV9II MINGW64 /f/Programming Learning/git learning (dev_testrebase)
 6 $ git diff
 7 
 8 lxl_lib1@DESKTOP-RGUV9II MINGW64 /f/Programming Learning/git learning (dev_testrebase)
 9 $ git status
10 On branch dev_testrebase
11 nothing to commit, working tree clean
12 
13 lxl_lib1@DESKTOP-RGUV9II MINGW64 /f/Programming Learning/git learning (dev_testrebase)
14 $ git checkout master
15 Switched to branch 'master'
16 
17 lxl_lib1@DESKTOP-RGUV9II MINGW64 /f/Programming Learning/git learning (master)
18 $ git status
19 On branch master
20 nothing to commit, working tree clean

 

rebase操作

rebase和merge相似,但是区别在于保留了更多的细节。从命令的名字就可以看出来,rebase是把当前的branch重置为为某一个版本(默认的是它所跟踪源branch的最新版本,即它是从哪里创建出来的,比如dev的源branch一般就是dev。也可以显式指定为别的branch),并把所做的修改看成是补丁(patch)。最后rebase成功后,用git log命令显示的版本号也是rebase_id>>patch1>>patch2>>patch3...(由旧到新)。merge操作的版本号这是按照各自修改的时间排序,如果有冲突并且解决了冲突后提交的merge,那么最后一个版本号是执行merge后提交的版本号。从这一点来看,rebase和merge最大的区别就是理念不同。一个是“重置”,一个是“合并”。

既然是重置,那么源branch可能和当时创建分支的时候相比,已经不一样的,比如,master已经有了其他人的提交,这时候就会产生冲突,冲突的结果有三种处理方式:--congtinue   --skip  --abort;

--continue:当手动处理好冲突之后,就使用continue,继续完成rebase,此时,就完成了合并。

--skip:就是强制rebase,把当前branch(dev)所做的修改全部放弃,直接回到创建之初的样子。

--abort:就是放弃这次rebase操作

stash操作

stash操作是在你新工作完成到一半时,测试发现原来版本有一个很关键bug要解决,而此时你不想将手头未完成的工作提交,只想在原来的版本上把bug修复,你可以用stash把未完成的工作先入栈,把工作区和index清理干净,然后你可以完成你的bug修复了。此时你有两种方式去修复bug,一种是在别的分支上修复(一般是在源分支上分离出一个新的bug分支完成后再rebase更新源分支),另一种是在当前分支上直接修复:

(1)第一种方式,等修复完成了,提交修复,源分支得到更新,bug得到了修复。你再用stash pop把之前未完成的新工作出栈,继续完成,完成之后提交,此时别忘了rebase一下,因为此时当前分支的上一个版本还是bug修复前的,所以要rebase到bug修复后的版本。完成这些后,你的当前版本就即修复了bug,又有了新功能了。

(2)第二种方式,如果修复bug时和新工作内容的文件有冲突,则需要解决冲突,然后再完成新工作,最后提交。

当前版本即有未commit 的index区,也有未add的工作区,都可以用stash入栈:

 1 $ git  status
 2 On branch master
 3 Changes to be committed:
 4   (use "git reset HEAD <file>..." to unstage)
 5 
 6         modified:   git learning.txt
 7 
 8 Changes not staged for commit:
 9   (use "git add <file>..." to update what will be committed)
10   (use "git checkout -- <file>..." to discard changes in working directory)
11 
12         modified:   git learning.txt
13 
14 
15 lxl_lib1@DESKTOP-RGUV9II MINGW64 /f/Programming Learning/git learning (master)
16 $ git stash
17 Saved working directory and index state WIP on master: a751bf2 merge dev_testrebase[1] into git learning.txt
18 
19 lxl_lib1@DESKTOP-RGUV9II MINGW64 /f/Programming Learning/git learning (master)
20 $ git status
21 On branch master
22 nothing to commit, working tree clean //可以看到,入栈之后,working tree 和index都被清空了

直接在当前分支修复bug时,stash pop 之后可能有冲突,此时git会把冲突文件合并,需要你去解决冲突,再完成工作,再提交:

$ git stash pop
Auto-merging git learning.txt
CONFLICT (content): Merge conflict in git learning.txt

lxl_lib1@DESKTOP-RGUV9II MINGW64 /f/Programming Learning/git learning (master)
$ git status
On branch master
Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add <file>..." to mark resolution)

        both modified:   git learning.txt

no changes added to commit (use "git add" and/or "git commit -a")

lxl_lib1@DESKTOP-RGUV9II MINGW64 /f/Programming Learning/git learning (master)
$ git add "git learning.txt"
lxl_lib1@DESKTOP-RGUV9II MINGW64 /f/Programming Learning/git learning (master)

  $ git commit
  [master 1e0a75e] handle confliction after unstash
   1 file changed, 4 insertions(+), 1 deletion(-)

 

                                                                                                                                 

                                                                                                                 图1    冲突                                                                                图2  冲突解决后

完成这些之后,修复bug的提交和新工件的提交都成功入了版本库了:

 1 lxl_lib1@DESKTOP-RGUV9II MINGW64 /f/Programming Learning/git learning (master)
 2 $ git log
 3 commit 1e0a75e5d287b2459609f33a5016e32d8cc24e3e (HEAD -> master) //新工作(其中包括了冲突解决)提交
 4 Author: xlinliu <kexuetou@163.com>
 5 Date:   Sat Sep 16 12:28:46 2017 +0800
 6 
 7     handle confliction after unstash  
 8 
 9 commit 4f2eae39dab242ca9a020e68a24b384fca96f4d4    //bug修复提交
10 Author: xlinliu <kexuetou@163.com>
11 Date:   Sat Sep 16 11:44:15 2017 +0800
12 
13     add master[5] after stash  

 和 .ignore设置有关的一些注意点

有如下结构目录

F:.
│  .gitignore
│  git learning.txt
│
├─path1
│  │  新建文本文档.txt
│  │
│  └─新建文件夹
│          新建文本文档.txt
│
└─path2
    │  file1.txt
    │  file2.txt
    │
    └─file.txt
            新建文本文档.txt

1   .ignore文件中例出的条目,/开头的表示根目录开始,理解为绝对路径,如 /path1/file.txt 指path1路径下的file.txt,;不带/的为任意的,如单独的  file.txt ,指任意位置的file.txt。

2.  以/结尾的条目表示目录,不带/结尾的表示一切。如 path.ext/ 表示path.ext/目录,只忽略path.ext/目录下的内容(包括文件和文件夹);而 path.ext 即会忽略path.ext/目录下的所有内容,也会忽略任意位置所以名为path.ext的文件

3.  至于path/*和path/的区别,事实就是效果没有区别,但又有本质区别。path/*是使用通配符的特例,匹配所有,所以和path/忽略所有效果一样,所以说效果没区别。但是path/*本质是通配符匹配,比如path/*a,则只匹配以a结尾的文件或文件夹,所以说有本质区别

//.ignore
1
path1/ 2 path2/file*

 

git update-index --assume-unchanged filename操作

    该命令用于commit时忽略当前分支特定文件的更改。后面只能跟具体文件名,而不能是文件夹。希望用文件夹来忽略文件夹下的所有文件的变化是行不通的。

    另外,这个操作的本意是,当某个文件特别大的时候,不想每次更改都让git去扫描它,因为这样会浪费很多时间,等到最终把这个大文件完成之后,在用--no-assume-unchanged回复跟踪,再一次性提交。但是这个操作只对本地库的当前分支有效,而且如果index发生了改变(比如reset了),此操作就失效,而且reset --hard操作还是会回复工作区。

    另一个类似的操作是--skip-worktree,这个操作是让git所有的操作都跳过指定文件,包括reset --hard。

    无论是 --assume-unchanged 还是 --skip-worktree,当文件有改动时,都不能进行rebase merge 以及切换分支等要求工作区和Index区是干净的操作(因为这些操作都会改变工作区,所以要求把工作区为提交的更改提交或者stash)。

关于远程库同步

远程分支用origin/branchname来表示,但是那只是一个远程库分支的复本,并不是远程库分支本身,所以要看到最新的远程库,必需用git fetch更新origin库。如果想把本地分支也更新,可以用切换到对应分支(目标分支),用 git merge origin/branchname 或者 git rebase orgin/branchname 命令和origin分支合并;也可以用 git pull 命令一次性完成fetch和merge。

IntelliJ idea 这个IDE也需要手动点fetch,origin分支才能更新。

posted on 2017-07-26 16:05  J.M.Liu  阅读(541)  评论(0编辑  收藏  举报