学习Git

常用命令

安装

  • 下载
  • 设置全局的 nameemail
       git config --global user.name "kadoufall"
       git config --global user.email "spuspu1997@gmail.com"
    
    • 全局的设置储存在 $HOME/.gitconfig 中,每次设置会覆盖之前的设置
    • 可以对每次仓库设置单独的 user.nameuser.email,去掉命令中的 --global 即可(在用到多个 Git 中心服务器时,例如自己开源项目传到 GitHub,公司代码传到 GitLab。与全局设置不同的仓库上传后不会被统计代码贡献,比如 GitHub 不会显示自己的头像)

初始化

创建新的 Git 仓库

$ git init
  • 执行后当前文件夹下会有一个新的子文件夹 .git
  • .git 文件夹所在的文件夹即为当前git的工作区

从既有仓库拷贝

$ git clone ~/existing/repo ~/new/repo
$ git clone git://host.org/project.git
$ git clone ssh://you@host.org/proj.git

工作流

本地仓库由 git 维护的三棵“树”组成

  • 第一个是工作目录,它持有实际文件
  • 第二个是 暂存区(Index),它像个缓存区域,临时保存你的改动
  • 最后是 HEAD,它指向你最后一次提交的结果

workflow-1

添加、提交

所有的修改初始时都在工作区

git add

将工作区的变化提交到暂存区

git-add

git commit

把暂存区的修改提交到当前分支,提交之后暂存区就被清空了

  • 注意
      第一次修改 -> git add -> 第二次修改 -> git commit
    

    这里第二次修改的不会在 commit 时被提交到,因为其未被放入暂存区中

    要 commit 两次修改,需要:

      第一次修改 -> git add -> 第二次修改 -> git add -> git commit
    
  • git commit -a 直接把所有文件的修改添加到暂缓区然后执行提交,等同于一步实现了 add 与 commit 的操作
  • git commit -m "messgae" 是添加该次 commit 的提交说明,commit message 有多种规范,例如 Angular规范

撤销、回滚、删除

git log

查看从最近到最远的 commit 日志

  • 日志较多时,可以使用 git log --pretty=oneline,该命令将一行显示一个 commit
  • git log --graph 命令可以看到分支合并图

git reset

  • 提交层面
    • 将一个分支的末端指向另一个提交。通常用于在私有分支上舍弃一些没有提交的更改
    • 三种模式
      • --soft 暂存区和工作目录都不会被改变
      • --mixed 默认选项。暂存区和你指定的提交同步,但工作目录不受影响
      • --hard 暂存区和工作目录都同步到你指定的提交
    • 常用操作 git reset --hard xxx 将 HEAD 移动到 xxx 提交,舍弃 xxx 之后的所有提交,并清空暂存区和工作区修改
    • git push origin HEAD --force 可以清除线上错误的 commit log
    • --hard 操作后,也可以重新 reset 到那些舍弃的提交去,只要知道那些提交的 commit id 就可以了
    • 要是不知道 commit id, 使用命令 git reflog 去看
  • 文件层面
    • 接受文件路径作为参数
    • 当检测到文件路径时,git reset 将暂存区同步到你指定的那个提交,即用于将文件从暂存区中移除
    • git reset HEAD~2 foo.java 将倒数第二个提交中的 foo.java 加入到暂存区中,供下一个提交使用
    • git reset README.md 将当前暂存区中的 README.md 文件移出,而不影响工作区

git checkout

  • 提交层面
    • 将 HEAD 移动到任意 commit id ,用于切换分支或查看旧版本
  • 文件层面
    • 作用域在工作区
    • git checkout HEAD~2 foo.java 将将工作目录中的 foo.java 同步到了倒数第二个提交中的 foo.java
    • git checkout README.md 舍弃 README.md 工作区没有缓存的更改

git revert

  • 撤销一个提交的同时会创建一个新的提交
  • 不会重写提交历史
命令 作用域 常用情景
git reset 提交层面 在私有分支上舍弃一些没有提交的更改
git reset 文件层面 将文件从暂存区中移除
git checkout 提交层面 切换分支或查看旧版本
git checkout 文件层面 舍弃工作目录中的更改
git revert 提交层面 在公共分支上回滚更改
git revert 文件层面 (然而并没有)

git rm

  • 从版本库中删除文件
  • 该命令是将更改添加到暂存区
  • 需要执行 commit 以提交到 HEAD

远程仓库

SSH 加密传输

  • SSH key 在 $HOME/.ssh 目录下;id_rsaid_rsa.pub 两个文件,前者为私钥,后者为公钥
  • 如果没有,使用下列命令创建
      ssh-keygen -t rsa -C "youremail@example.com"
    

    然后把公钥 id_rsa.pub 的内容复制到 Github “Account settings” 的 SSH Keys 中

  • 配置多个 SSH key
    • 适用于有多个 GitHub 账号,或同时有 GitLab 时
    • 生成新的 SSH key
        # 新建 SSH key
        $ cd ~/.ssh 
        $ ssh-keygen -t rsa -C "myWork@email.com"  # 新建工作的 SSH key
        # 设置名称为id_rsa_work
        Enter file in which to save the key (~/.ssh/id_rsa): id_rsa_work
      
    • $HOME/.ssh 目录下新建 config 文件,内容例如 ```bash # 该文件用于配置私钥对应的服务器 # Default github user(first@mail.com) Host github.com HostName github.com User 624938994@qq.com PreferredAuthentications publickey IdentityFile $HOME/.ssh/id_rsa

    # second user(second@mail.com) Host gitlab.com HostName gitlab.com User spuspu1997@gmail.com PreferredAuthentications publickey IdentityFile $HOME/.ssh/id_rsa_work

      - 在特定工作目录下设置其对应的 git config
      ```bash
      git config user.name "yourName" 
      git config user.email "yourEmail" 
    

添加远程仓库

git remote add origin <server>

推送改动

  • 远程仓库为空时需要添加 -u 参数,Git 不但会把本地的 master 分支内容推送的远程新的 master 分支,还会把本地的 master 分支和远程的 master 分支关联起来
      git push -u origin master
    
  • 后续推送不需要带参数,可将 master 替换为任意分支
      git push origin master
    

参看远程仓库信息

git remote -v

分支

创建、参看、删除

git checkout -b <branchName> 创建分支,-b 参数表示创建并切换

$ git checkout -b dev
Switched to a new branch 'dev'
  • 等同于
      $ git branch dev
      $ git checkout dev
      Switched to branch 'dev'
    

git checkout <branchName> 切换分支

git branch 查看当前分支,当前分支前面会标一个 *

$ git branch
* dev
  master

git branch -a 参看所有分支,包括远程仓库的分支

git branch -d <branchName> 删除分支

合并、冲突

git merge <branchName> 合并其他分支到当前分支

合并可能出现冲突,冲突形式如下

<<<<<<< HEAD
Creating a new branch is quick & simple.
=======
Creating a new branch is quick AND simple.
>>>>>>> feature1
  • 处理完分支后,依次 add 与 commit 完成本次合并
  • 在合并改动之前,可使用如下命令预览差异:
      git diff <source_branch> <target_branch>
    

Fast forward

  • “快进式合并”(fast-farward merge),会直接将 master 分支指向合并的分支,这种模式下进行分支合并会丢失分支信息,也就不能在分支历史上看出分支信息
  • 可以在合并时加上 –no-ff 参数来禁用 Fast forward 模式,并且加上 -m 参数让合并时产生一个新的 commit。
      $ git merge --no-ff -m "merge with no-ff" dev
    

连接远程分支

  • git push origin <branchName> 推送本地分支到远程
  • 推动失败时,需要 pull 或者 rebase,后续详述
  • git checkout -b <branchName> <origin/branchName> 在本地创建和远程分支对应的分支
  • git branch --set-upstream <branchName> <origin/branchName> 建立本地分支和远程分支的关联(如果 git pull 提示 “no tracking information”)

pull、rebase

git pull = git fetch + git merge
git pull --rebase = git fetch + git rebase
  • rebase 中会出现冲突,解决冲突后使用 git add '文件名' 更新索引
  • 使用 git rebase --continue 完成 rebase
  • 使用 git rebase --abort 停止 rebase

一个可行的操作是

  • git fetch
  • git checkout -b someBranch,从 dev 分支切一个 bug 或 feature 分支
  • git rebase origin/dev
  • 开始开发
  • 完成后 git pull –rebase origin/dev
  • 提一个PR,origin/dev 来 merge 之前那个分支
  • 删除之前那个分支

rebase 优缺点

  • 使得 commit log 简洁好看,没有一堆 merge conflict
  • 可能会有很多的冲突去解决
  • 需要及时 rebase 上游分支

分支管理

  • master 分支应该是非常稳定的,只用来发布新版本
  • 日常开发在开发分支 dev 上进行
  • bug 分支用于修复 bug,git checkout -b fixbug/issueName
  • feature 分支用于实现 feature,git checkout -b feature/featureName
  • 可以使用 git-flow

储藏(Stashing)

在一个分支上操作之后,如果还没有将修改提交到分支上,此时进行切换分支,那么另一个分支上也能看到新的修改。这是因为所有分支都共用一个工作区的缘故。

可以使用 git stash 将当前分支的修改储藏起来,此时当前工作区的所有修改都会被存到栈上,也就是说当前工作区是干净的,没有任何未提交的修改。此时就可以安全的切换到其它分支上了。

$ git stash
Saved working directory and index state \ "WIP on master: 049d078 added the index file"
HEAD is now at 049d078 added the index file (To restore them type "git stash apply")

该功能可以用于 bug 分支的实现。如果当前正在 dev 分支上进行开发,但是此时 master 上有个 bug 需要修复,但是 dev 分支上的开发还未完成,不想立即提交。在新建 bug 分支并切换到 bug 分支之前就需要使用 git stash 将 dev 分支的未提交修改储藏起来。

git stash list 命令看看储藏的工作区

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

git stash apply 恢复工作区,但是恢复后,stash 内容并不删除,你需要用 git stash drop 来删除

git stash apply stash@{0}

git stash pop,恢复的同时把 stash 内容也删了

标签

git tag <name> <commmitID>

创建新建一个标签,默认为 HEAD ,也可以指定一个 commit id

git tag -a <tagName> -m "message"

指定标签信息

git tag -s <tagName> -m "message"

用PGP签名标签

git tag

查看所有标签

git show <tagName>

查看标签信息

git push origin <tagName>

推送一个本地标签

git push origin --tags

推送全部未推送过的本地标签

git tag -d <tagName>

删除一个本地标签

git push origin :refs/tags/<tagName>

删除一个远程标签

.gitignore

忽略以下文件:

  • 操作系统自动生成的文件,比如缩略图
  • 编译生成的中间文件,比如 Java 编译产生的 .class 文件
  • 自己的敏感信息,比如存放口令的配置文件

到 https://github.com/github/gitignore 中查

学习资料