Git

1. 版本控制系统

版本控制:按时间顺序记录某一个或一系列文件的变更,可以查看以前的特定版本

git基础

安装git

sudo apt-get install git-all

首次配置

2. git基础

git commit --amend #提交暂存区内容到上一次提交中,重新编辑提交信息
git reset HEAD <file> #把文件从缓存区中移除
git chechout -- <file> #检出上次提交中的文件覆盖已做更改的文件

3. 分支机制

​ 分支简介 ​ 分支就是一个只向提交的指针,根据提交的父对象生成提交链

  1. 创建新的分支

    创建一个新的指针指向当前提交, 因此git分支高效快速

    其中git维护的HEAD指针指向当前所在的本地指针的分支

    git branch [branch-name] #在HEAD指针指向提交创建分支
    		  -d [branch-name] #删除分支
    
    rick@DESKTOP-M0096T1:~/learn_git/test_dir1$ git branch test-branch
    rick@DESKTOP-M0096T1:~/learn_git/test_dir1$ git log --oneline --decorate      
    1e5f078 (HEAD -> master, test-branch) update LICENSE                          
    e7ab412 update README                                                         
    3fe2e5d initial commit 
    
  2. 切换分支

    切换分支即改变HEAD指针指向的位置, 使其指向新的分支

    继续提交会形成分支

    切换分支会改变工作目录文件

    git chechout [branch-name]或[SHA-1]
    			-b #分支不存在,先创建分支,再切换
    
    rick@DESKTOP-M0096T1:~/learn_git/test_dir1$ git log --all --oneline --graph
    * 7087854 (master) how old version of test.c
    | * 5f59182 (HEAD -> test-branch) hello-world version of test.c
    |/
    * 1e5f078 update LICENSE
    * e7ab412 update README
    * 3fe2e5d initial commit
    
  3. 合并分支

    git merge [branch-name] #合并分支到当前分支中(HEAD)
    					  #记得使用git branch -d ... 删除被合并的分支保持简洁
    
    • Fast-forward: 当前分支在被合并分支的直接上游, 直接将当前指针前移

    • 合并提交: git自行判断最优共同祖先, 以其为基础合并, 合并的提交有两个父提交

    • 合并冲突: 处理冲突, 再次提交

      rick@DESKTOP-M0096T1:~/learn_git/test_dir1$ git checkout master
      Switched to branch 'master'
      rick@DESKTOP-M0096T1:~/learn_git/test_dir1$ git merge test-branch
      Auto-merging test.c
      CONFLICT (content): Merge conflict in test.c
      Automatic merge failed; fix conflicts and then commit the result.
      rick@DESKTOP-M0096T1:~/learn_git/test_dir1$ git status
      On branch master
      You have unmerged paths.
        (fix conflicts and run "git commit")
        (use "git merge --abort" to abort the merge)
            
      Unmerged paths:
        (use "git add <file>..." to mark resolution)
            
              both modified:   test.c
            
      no changes added to commit (use "git add" and/or "git commit -a")
      

      image-20210123011252639.png

      rick@DESKTOP-M0096T1:~/learn_git/test_dir1$ git commit
      U       test.c
      error: Committing is not possible because you have unmerged files.
      hint: Fix them up in the work tree, and then use 'git add/rm <file>'
      hint: as appropriate to mark resolution and make a commit.
      fatal: Exiting because of an unresolved conflict.
      rick@DESKTOP-M0096T1:~/learn_git/test_dir1$ git add test.c
      rick@DESKTOP-M0096T1:~/learn_git/test_dir1$ git status
      On branch master
      All conflicts fixed but you are still merging.
        (use "git commit" to conclude merge)
      rick@DESKTOP-M0096T1:~/learn_git/test_dir1$ git commit
      [master 6ee19b3] Merge branch 'test-branch'
      rick@DESKTOP-M0096T1:~/learn_git/test_dir1$ git log --oneline --all --graph
      *   6ee19b3 (HEAD -> master) Merge branch 'test-branch'
      |\
      | * 5f59182 (test-branch) hello-world version of test.c
      * | 7087854 how old version of test.c
      |/
      * 1e5f078 update LICENSE
      * e7ab412 update README
      * 3fe2e5d initial commit
      rick@DESKTOP-M0096T1:~/learn_git/test_dir1$ git branch -d test-branch
      Deleted branch test-branch (was 5f59182).
      
  4. 管理分支

    git branch #显示所有的分支, 使用星号(*)标注当前分支
    		  -v #查看分支上的最新提交
    		  --merged #已经合并的分支,建议删除这些分支
    		  --no-merged #还未合并的分支,尝试删除时,给git因还未合并而显示删除失败
    
  5. 分支工作流

    • 长期分支工作流: 主分支(master)保留稳定性最高, develop, next, proposed分支稳定性低,进行前沿开发
    • 主题分支: 为实现不同功能创建不同分支
  6. 远程分支

    表达形式:[remote-name]/[branch}

    git远程仓库指令

    git clone [url] [project-name] 		  #name为代替项目文件夹默认名称的名称
    		-o [remote-name] 			#远程分支使用中,代替默认origin的名称
    git remote -v 						#显示所有远程仓库,和对应的URL
    git remote add [remote-name] [url] 	  #添加远程仓库
    git fetch [remote-name] 			 #从远程仓库拉取数据
    		--all #从所有远程仓库中拉取数据
    		-u #设置为追踪分支
    git push [remote-name] [branch-name]  #将数据推送到远程仓库
    git remote show [remote-name] 		 #显示远程仓库的详细信息
    git remote rename [new-name] [remote-name]  
    								   #重命名
    git remote rm [remote-name]           #删除远程仓库
    

    clone一个远程仓库

    rick@DESKTOP-M0096T1:~/learn_git$ git clone https://github.com/luxianche-studypath/test_dir_remote1.git
    Cloning into 'test_dir_remote1'...
    Username for 'https://github.com': luxianche-studypath
    Password for 'https://luxianche-studypath@github.com':
    remote: Enumerating objects: 7, done.
    remote: Counting objects: 100% (7/7), done.
    remote: Compressing objects: 100% (5/5), done.
    remote: Total 7 (delta 0), reused 0 (delta 0), pack-reused 0
    Unpacking objects: 100% (7/7), done.
    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ git log --oneline
    83b89fd (HEAD -> main, origin/main, origin/HEAD) Create LICENSE
    e30eb27 Create README.md
    

    自己在本地上工作, 产生新的提交, main和origin/main偏离

    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ touch test2.c
    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ git add test2.c
    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ git commit -m "CREATE test2.c"
    [main 0b1b4e3] CREATE test2.c
     1 file changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 test2.c
    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ git log --oneline
    0b1b4e3 (HEAD -> main) CREATE test2.c
    83b89fd (origin/main, origin/HEAD) Create LICENSE
    e30eb27 Create README.md
    

    其他人推送数据以后, fetch整个远程仓库中的追踪分支的更新内容(默认为master), 与服务器同步, 更新origin/main位置

    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ git fetch origin
    Username for 'https://github.com': luxianche-studypath
    Password for 'https://luxianche-studypath@github.com':
    remote: Enumerating objects: 4, done.
    remote: Counting objects: 100% (4/4), done.
    remote: Compressing objects: 100% (3/3), done.
    remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
    Unpacking objects: 100% (3/3), done.
    From https://github.com/luxianche-studypath/test_dir_remote1
       83b89fd..48e96e3  main       -> origin/main
    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ git log --oneline --all --graph
    * 0b1b4e3 (HEAD -> main) CREATE test2.c
    | * 48e96e3 (origin/main, origin/HEAD) Create test.c
    |/
    * 83b89fd Create LICENSE
    * e30eb27 Create README.md
    

    在使用多个远程仓库时, 假设存在敏捷开发小组teamone, 使用git remote add添加到当前项目中.

    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ git remote add teamone https://github.com/luxianche-studypath/test_dir_remote_teamone.git
    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ git remote
    origin
    teamone
    

    同样fetch teamone的最新进度

    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ git fetch teamone
    Username for 'https://github.com': luxianche-studypath
    Password for 'https://luxianche-studypath@github.com':
    remote: Enumerating objects: 4, done.
    remote: Counting objects: 100% (4/4), done.
    remote: Compressing objects: 100% (2/2), done.
    remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
    Unpacking objects: 100% (3/3), done.
    From https://github.com/luxianche-studypath/test_dir_remote_teamone
     * [new branch]      main       -> teamone/main
    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ git log --oneline --all --graph
    * bed69a9 (teamone/main) Create test3.c
    | * 0b1b4e3 (HEAD -> main) CREATE test2.c
    |/
    | * 48e96e3 (origin/main, origin/HEAD) Create test.c
    |/
    * 83b89fd Create LICENSE
    * e30eb27 Create README.md
    

    fetch到的分支无法直接修改, 使用merge或checkout -b创建本地的分支再进行修改

    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ git merge teamone/main
    Merge made by the 'recursive' strategy.
     test3.c | 1 +
     1 file changed, 1 insertion(+)
     create mode 100644 test3.c
    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ git merge origin/main
    Merge made by the 'recursive' strategy.
     test.c | 19 +++++++++++++++++++
     1 file changed, 19 insertions(+)
     create mode 100644 test.c
    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ git log --oneline --all --graph
    *   90cec37 (HEAD -> main) Merge remote-tracking branch 'origin/main' into main
    |\
    | * 48e96e3 (origin/main, origin/HEAD) Create test.c
    * |   98c52e7 Merge remote-tracking branch 'teamone/main' into main
    |\ \
    | * | bed69a9 (teamone/main) Create test3.c
    | |/
    * | 0b1b4e3 CREATE test2.c
    |/
    * 83b89fd Create LICENSE
    * e30eb27 Create README.md
    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ ls
    LICENSE  README.md  test.c  test2.c  test3.c
    

    push自己的本地工作成果到服务器中与他人分享

    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ git commit
    [main 010096e] Creat test4.c
     1 file changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 test4.c
    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ git push origin main
    Username for 'https://github.com': luxianche-studypath
    Password for 'https://luxianche-studypath@github.com':
    Counting objects: 2, done.
    Delta compression using up to 8 threads.
    Compressing objects: 100% (2/2), done.
    Writing objects: 100% (2/2), 263 bytes | 263.00 KiB/s, done.
    Total 2 (delta 1), reused 0 (delta 0)
    remote: Resolving deltas: 100% (1/1), completed with 1 local object.
    To https://github.com/luxianche-studypath/test_dir_remote1.git
       90cec37..010096e  main -> main
    rick@DESKTOP-M0096T1:~/learn_git/test_dir_remote1$ git log --oneline --all --graph
    * 010096e (HEAD -> main, origin/main, origin/HEAD) Creat test4.c
    *   90cec37 Merge remote-tracking branch 'origin/main' into main
    |\
    | * 48e96e3 Create test.c
    * |   98c52e7 Merge remote-tracking branch 'teamone/main' into main
    |\ \
    | * | bed69a9 (teamone/main) Create test3.c
    | |/
    * | 0b1b4e3 CREATE test2.c
    |/
    * 83b89fd Create LICENSE
    * e30eb27 Create README.md
    

    跟踪分支: git将会知道push到哪去和从哪里fetch,默认情况, 自动创建跟踪着origin/master的本地master分支, 自己创建跟踪其他分支(比如说master侧面的功能分支或前沿开发分支)

    git chechout -b [branch] [remote-name]/[remote-branch] #切换到分支中
    git chechout --track [remote-name]/[remote-branch] #切换到分支中
    git chechout [remote-branch] #切换到只有服务器存在的分支,自动创建跟踪分支,获取数据
    git branch -u [remote-name]/[remote-branch] #给本地已存在分支设置远程分支
    
    git branch -vv #查看已跟踪的分支,显示领先/落后提交数(仅提供本地缓存中的信息)
       
    git fetch --all #获取全部远程数据
    git branch --vv #从而查看最新数据
    

    删除远程分支

    git push [remote-name] --delete [branch-name]
    

    不用每次都输入密码:

    git config --global credential.helper cache
    #缓存密码一段时间
    
  7. 变基

    为了获得整洁的提交历史, 把分支上commit的所有diff在共同祖先基础上在目标分支中重复一遍,抛弃某些已有的链接, 创建了新的对应提交

    git rebase [base-branch] [topic-branch]
    git checkout [base-branch]
    git merge [topic-branch]
    git branch -d [topic-branch] #一套操作把提交历史修改成线
    

    一个有趣的例子?

    问题: 仅变基client分支

    git rebase --onto master server client
    

    效果:

    变基的危害:

    不要对已经存在于本地仓库以外的提交执行变基操作

4. Git服务器

先确保服务器上安装了git-core,ssh

sudo apt-get install wget git-core
sudo apt-get install ssh
sudo /etc/init.d/ssh start #启动ssh
sudo update-rc.d ssh defaults #ssh默认启动

添加用户git方便管理

sudo adduser --system --shell /bin/bash --gecos 'git version control' --group --home /home/git git
sudo passwd git
  1. 建立裸仓库裸仓库(没有工作目录)

    按照惯例,裸仓库后缀.git

    • 在已有仓库的基础上

      git clone --bare my_project my_project.git
      #上述操作等同于
      cp -Rf my_project/.git my_project.git
      
    • 新建

      mkdir test.git
      cd test.git
      git --bare init
      		--shared #为用户做赋予写权限
      
  2. 仓库放置在服务器上

    scp -r my_project user@git.example.com:/srv/git
    

    我的实例:

    scp -r learn_c.git git@192.168.10:/home/git
    

5. 分布式git

为项目做贡献

提交准则:

  1. 每次提交都是一个独立的变更集

  2. 创建高质量的提交信息

    简要的变更汇总说明(不超过50字)
       
    相近的说明(每行超过72字)
    变更的动机
    实现之前与之后的对比
    语言表述使用命令,不添加主语,保持简洁
       
    	- 使用这样的条目符号
    	- 表示列表和其他信息