• 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分支才能更新。

  • 相关阅读:
    Java 默认修饰符
    大学生职业规划到底应该规划什么?
    IT就业攻略:看准趋势 选对行业
    积极推动校企深度合作 做好产学结合示范工作
    强化工程实践能力 提升就业核心竞争力
    大学生就业:以“硬”实力实现“软”着陆
    使用IDEA 创建SpringBoot项目
    项目记录随笔
    全国城市数据库sql
    xp win7共享
  • 原文地址:https://www.cnblogs.com/JMLiu/p/7240218.html
Copyright © 2020-2023  润新知