• 微信小程序已经跑起来了.快捷键设置找了好久没找到,完全凭感觉.图贴出来.大家看看. 我现在用的是0.10.101100的版本,后续版本更新快捷键也应该不会有什么变化. 现在貌似不能修改.如果有同学找到修改的方法,...

    微信小程序已经跑起来了.快捷键设置找了好久没找到,完全凭感觉.图贴出来.大家看看.

    我现在用的是0.10.101100的版本,后续版本更新快捷键也应该不会有什么变化.



    现在貌似不能修改.如果有同学找到修改的方法,麻烦告诉我.谢谢.

    微信小程序代码编辑快捷键

    常用快捷键

    格式调整

    • Ctrl+S:保存文件
    • Ctrl+[, Ctrl+]:代码行缩进
    • Ctrl+Shift+[, Ctrl+Shift+]:折叠打开代码块
    • Ctrl+C Ctrl+V:复制粘贴,如果没有选中任何文字则复制粘贴一行
    • Shift+Alt+F:代码格式化
    • Alt+Up,Alt+Down:上下移动一行
    • Shift+Alt+Up,Shift+Alt+Down:向上向下复制一行
    • Ctrl+Shift+Enter:在当前行上方插入一行

    光标相关

    • Ctrl+End:移动到文件结尾
    • Ctrl+Home:移动到文件开头
    • Ctrl+i:选中当前行
    • Shift+End:选择从光标到行尾
    • Shift+Home:选择从行首到光标处
    • Ctrl+Shift+L:选中所有匹配
    • Ctrl+D:选中匹配
    • Ctrl+U:光标回退

    界面相关

    • Ctrl + \:隐藏侧边栏


    展开全文
  • git 误删分支恢复方法

    2018-12-10 14:52:47
    Sheel代码    git branch abc    2.查看分支列表 Sheel代码    git branch -a   abc  * develop   remotes/origin-dev/develop    3.切换到abc分支,随便修改一下东西后 commit Sheel...

    1.创建分支 abc

    Sheel代码 

     收藏代码

    1. git branch abc  

     
    2.查看分支列表

    Sheel代码 

     收藏代码

    1. git branch -a  
    2.   abc  
    3. * develop  
    4.   remotes/origin-dev/develop  

     
    3.切换到abc分支,随便修改一下东西后 commit

    Sheel代码 

     收藏代码

    1. # 切换分支  
    2. git checkout abc  
    3.   
    4. # 创建一个文件  
    5. echo 'abc' > test.txt  
    6.   
    7. # 提交  
    8. git add .  
    9. git commit -m 'add test.txt'  

     
    4.删除分支abc

    Sheel代码 

     收藏代码

    1. git branch -D abc  

     
    5.查看分支列表,abc分支已不存在

    Sheel代码 

     收藏代码

    1. git branch -a  
    2. * develop  
    3.   remotes/origin-dev/develop  

     
    恢复步骤如下:
    1.使用git log -g 找回之前提交的commit

    Sheel代码 

     收藏代码

    1. commit 3eac14d05bc1264cda54a7c21f04c3892f32406a  
    2. Reflog: HEAD@{1} (fdipzone <fdipzone@sina.com>)  
    3. Reflog message: commit: add test.txt  
    4. Author: fdipzone <fdipzone@sina.com>  
    5. Date:   Sun Jan 31 22:26:33 2016 +0800  
    6.   
    7.     add test.txt  

     
    2.使用git branch recover_branch[新分支] commit_id命令用这个commit创建一个分支

    Sheel代码 

     收藏代码

    1. git branch recover_branch_abc 3eac14d05bc1264cda54a7c21f04c3892f32406a  
    2.   
    3. git branch -a  
    4. * develop  
    5.   recover_branch_abc  
    6.   remotes/origin-dev/develop  

     
    3.切换到recover_branch_abc分支,检查文件是否存在

    Sheel代码 

     收藏代码

    1. git checkout recover_branch_abc  
    2. Switched to branch 'recover_branch_abc'  
    3.   
    4. ls -lt  
    5. total 8  
    6. -rw-r--r--   1 fdipzone  staff     4  1 31 22:38 test.txt  

     

    https://blog.csdn.net/fdipzone/article/details/50616386

    展开全文
  • 版本管理-Git

    2019-04-12 16:42:26
    https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/0013743256916071d599b3aed534aaab22a0db6c4e07fd0000 Git是目前世界上最先进的分布式版本控制系统(没有之一)。...

    https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/0013743256916071d599b3aed534aaab22a0db6c4e07fd0000

    Git是目前世界上最先进的分布式版本控制系统(没有之一)。

     

    安装Git 创建初始化仓库

     

    安装Git...  

     

    使用

    Plain Text

     

     

    
     

    1

    $ git add file1.txt

    2

    $ git add file2.txt file3.txt

    3

    $ git commit -m "add 3 files."

     

    现在总结一下今天学的两点内容:

    创建一个文件夹

    初始化一个Git仓库,使用git init命令。

    添加文件到Git仓库,分两步:

    1. 使用命令git add <file>,注意,可反复多次使用,添加多个文件;
    2. 使用命令git commit -m <message>,完成。

     

    git status命令可以让我们时刻掌握仓库当前的状态

    git diff file 顾名思义就是查看difference查看修改内容

     

    • 要随时掌握工作区的状态,使用git status命令。
    • 如果git status告诉你有文件被修改过,用git diff可以查看修改内容。

     

     

     

     

    时空机穿梭

     

    HEAD 版本切换

    现在总结一下:

     

    • HEAD指向的版本就是当前版本,因此,Git允许我们在版本的历史之间穿梭,
    • 使用命令git reset --hard commit_id
    • 回退当前版本的上一个版本 
    •  
    • 穿梭前,用git log可以查看提交历史,以便确定要回退到哪个版本。
    • 要重返未来,用git reflog查看命令历史,以便确定要回到未来的哪个版本。

          git reset --hard HEAD^  回退上一个版本

     查看日志:

    Git

     

     

    
     

    1

    git log --graph --pretty=oneline --abbrev-commit

     

     

    暂存区的了解,明白Git的操作是怎么回事儿

     

    暂存区是Git非常重要的概念,弄明白了暂存区,就弄明白了Git的很多操作到底干了什么。

    image.png                             ​

    第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;  stage

    第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。 master /  other branch 

    Git核心是跟踪 修改

    现在,你又理解了Git是如何跟踪修改的,每次修改,如果不用git add到暂存区,那就不会加入到commit中。

     

    撤销工作区内容和暂存区内容

     

    又到了小结时间。

    场景1:当你改乱了工作区某个文件的内容,想直接丢弃工作区的修改时,用命令git checkout -- file

    场景2:当你不但改乱了工作区某个文件的内容,还添加到了暂存区时,想丢弃修改,分两步,

    第一步用命令git reset HEAD <file>,就回到了场景1,第二步按场景1操作。

    场景3:已经提交了不合适的修改到版本库时,想要撤销本次提交,参考版本回退一节,不过前提是没有推送到远程库。

    删除文件

     

    命令git rm <file>用于删除版本库里的一个文件。如果一个文件已经被提交到版本库,那么你永远不用担心误删,但是要小心,你只能恢复文件到最新版本,你会丢失最近一次提交后你修改的内容

    rm <file> 用于删除工作区的文件  ;  如果误删了,版本库里面还有呢,用

    git checkout -- <file>  还原

    git checkout 其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”

     

     

     

     

    远程仓库

     

    远程库- 注册GitHub 把本地关联到远程库

    要关联一个远程库,

    使用命令git remote add origin git@server-name:path/repo-name.git

    path是 GitHub账号名

    关联后,使用命令git push -u origin master第一次推送master分支的所有内容;

    此后,每次本地提交后,只要有必要,就可以使用命令git push origin master推送最新修改;

    分布式版本系统的最大好处之一是在本地工作完全不需要考虑远程库的存在,也就是有没有联网都可以正常工作,而SVN在没有联网的时候是拒绝干活的!当有网络的时候,再把本地提交推送一下就完成了同步,真是太方便了!

     

    从远程仓库克隆到本地

    使用命令 

    Plain Text

     

     

    
     

    1

    git clone git@github.com:GitHub账户名/gitskills.git (文件名)

    要克隆一个仓库,首先必须知道仓库的地址,然后使用git clone命令克隆。

    Git支持多种协议,包括https,但通过ssh支持的原生git协议速度最快。

    参数: --depth=1 

    depth用于指定克隆深度,为1即表示只克隆最近一次commit.

     

     

    分支管理

     

    创建切换分支  合并分支

    Git鼓励大量使用分支:

    查看本地分支:git branch

    查看远程库分支:git branch -r  

    查看本地 和 远程库分支:git branch -a 

    创建分支:git branch <name>

    切换分支:git checkout <name>

    创建+切换分支:git checkout -b <name>

    合并某分支到当前分支:git merge <name>  但会丢掉分支的信息

    合并某分支到当前分支  带 --no-ff参数  和 -m “”添加合并信息的描述:

    git merge --no-ff -m "message" <name>  

     

     

    删除分支:git branch -d <name>

    删除远程库分支:git push origin -d <name>

     

    从远程库拉取分支:git pull

     

    从查看分支合并信息:git log --graph

     

     

     

    分支合并冲突解决

    当混帐无法自动合并分支时,就必须首先解决冲突。解决冲突后,再提交,合并完成。

    解决冲突就是把Git的合并失败的文件手动编辑为我们希望的内容,再提交。

    git log --graph命令可以看到分支合并图产品。

     

    分支管理策略

     


    image.png                             ​

    Git分支十分强大,在团队开发中应该充分应用。

    合并分支时,加上--no-ff参数就可以用普通模式合并,合并后的历史有分支,能看出来曾经做过合并,而fast forward合并就看不出来曾经做过合并。

     

     


    image.png                             ​

     

     

     

    Bug分支

    突然要修bug

    先把正在开发的现场暂停保存一下

    工作现场git stash一下,  修好后回来 git stash pop 回到工作现场

     

     

    修复bug时,我们会通过创建新的bug分支进行修复,然后合并,最后删除;

    当手头工作没有完成时,先把工作现场git stash一下,然后去修复bug,修复后,再git stash pop,回到工作现场。

     

     

    开发新功能,创建新的分支

    开发一个新feature,最好新建一个分支;

    如果要丢弃一个没有被合并过的分支,可以通过git branch -D <name>强行删除。

     

     

    多人协作 

    • 查看远程库信息,使用git remote -v
    • 本地新建的分支如果不推送到远程,对其他人就是不可见的;
    • 从本地推送分支,使用git push origin branch-name,如果推送失败,先用git pull抓取远程的新提交;
    • 在本地创建和远程分支对应的分支,使用git checkout -b branch-name origin/branch-name,本地和远程分支的名称最好一致;
    • 建立本地分支和远程分支的关联,使用git branch --set-upstream branch-name origin/branch-name
    • 从远程抓取分支,使用git pull,如果有冲突,要先处理冲突。

     

    标签管理

     

    • 命令git tag <tagname>用于新建一个标签,默认为HEAD,也可以指定一个commit id;
    • 命令git tag -a <tagname> -m "blablabla..."可以指定标签信息;
    • 命令git tag可以查看所有标签。

    操作标签 

    • 命令git push origin <tagname>可以推送一个本地标签;
    • 命令git push origin --tags可以推送全部未推送过的本地标签;
    • 命令git tag -d <tagname>可以删除一个本地标签;
    • 命令git push origin :refs/tags/<tagname>可以删除一个远程标签。
    展开全文
  • 小猪的Git使用总结

    2017-11-22 22:35:16
    厉害了!小猪用Git一年多后的精华总结标签: Git描述性文字:不要问我为什么用这种骚猪风格的标题,现在...比如自己搭建啊,一些便利工具的使用啊,一些疑难杂症解决方案啊等等,当然 这就是下一话的事了。本文讲述的

    小猪的Git使用总结



    目录


    概述

    接触Git也些年头了,对于Git的使用也算是略有心得,想着
    出于自己日后回顾,也便于他人查阅学习的目的,遂有此文,
    相信看完此文你的Git使用会更进一步,谢谢~

    PS:有些童鞋曾私信问我为什么有图形化的Git工具还要学
    命令行,原因挺多的,我觉得最主要的原因有三点:

    • 1.减少跨平台使用Git成本,不用另外花时间去熟悉各种工具;
    • 2.知道原理,出问题的时候不会一脸懵逼;
    • 3.装逼,敲起来命令噼里啪啦,不知道还以为你真的是大神;

    在线版(排版更佳,优先更新):https://www.zybuluo.com/coder-pig/note/581320
    本文不收取任何费用,欢迎转载,但请注明原文出处!
    禁止将本文用于商业用途,想了解更多内容可见:
    http://blog.csdn.net/coder_pig
    如果本文对你学习Git有一定帮助,不妨小额打赏下小猪,
    你的鼓励是我不断写博客的动力, 万分感谢~

    微信: 支付宝:

    如有什么疑问欢迎加群:421858269 反馈,谢谢~


    安装配置与文档


    1.下载安装

    • Windows系统:到 Git For Windowsgit-for-windows.github.io下载,傻瓜式下一步。
    • Linux系统:到 Download for Linux and Unix 下载,如果是Ubuntu的话,直接Terminal键入:
      sudo apt-get install git 安装。
    • Mac系统:到 Installing on Mac 下载,不过新系统貌似默认已经带有Git了,另外如果安装了
      Homebrew的话可以直接命令行键入:brew install git 进行安装。

    2.文档教程相关


    概念


    1.Git的四个组成部分

    2.文件的几个状态

    按大类划分,分为两种状态:Tracked(已跟踪)和Untracked(未跟踪),
    依据是:该文件是否已加入版本控制

    流程简述:

    假设某个项目已加入版本控制系统

    • 1.新建一个文件,该文件处于 Untracked 状态;
    • 2.通过git add命令添加到缓存区,此时文件处于Tracked状态又或者说
      此时这个文件已经被版本控制系统所跟踪,而且他处于Staged(暂存)状态;
    • 3.通过git commit命令把暂存区的文件提交提交到本地仓库,此时文件
      处于Unmodified(未修改)状态;
    • 4.此时如果去编辑这个文件,文件又会变成Modified(修改)状态;

    3.Git与SVN版本版本控制存储差异

    Git关心的是:文件整体是否发生变化,而SVN关心的是:文件内容的具体差异!
    SVN每次提交记录的是:哪些文件进行了修改,以及修改了哪些行的哪些内容

    如图:版本2中记录的是文件A和C的变化,而版本3中记录文件C的变化,以此类推;
    而Git中,并不保存这些前后变化的差异数据,而是保证整个缓存区中的所有文件,
    又叫快照,有变化的文件保存没变化的文件不保存而是对上一次的保存的快照
    做一个链接!因为这种不同的保存方式,Git切换分支的速度比SVN快很多!

     

    4.每次Commit时仓库中的数据结构

    分为四个对象:

    blob对象:存放文件数据;
    tree对象:目录,内容为blob对象的指针或其他tree对象的指针
    commit对象:快照,包含指向前一次提交对象的指针,commit相关的信
    通过索引找到文件快照。
    tag对象:一种特殊的commit对象,一般对某次重要的commit加TAG,以示重要(方便找)


    本地操作命令


    1.相关配置【git config】

    区分globallocal,前者代表 全局设置,就是设置了在整个系统中,
    所有的带Git版本管理的项目都是这样的配置;后者代表 本地设置
    即在某个项目中独立的设置,后者优先级高于前者。比如全局设置
    的用户名是”Coder-pig”,本地设置的是”Jay”,commit的时候author
    就是Jay而不是Coder-pig。除了通过命令行修改,还可以直接修改
    对应文件:

    全局配置文件:etc/gitconfig (Mac下是隐藏文件,用户/.gitconfig)
    本地配置文件:当前仓库/.git/config

    # 安装完Git后第一件要做的事,设置用户信息(global可换成local在单独项目生效):
    git config --global user.name "用户名" # 设置用户名
    git config --global user.email "用户邮箱"   #设置邮箱
    git config --global user.name   # 查看用户名是否配置成功
    git config --global user.email   # 查看邮箱是否配置
    
    # 其他查看配置相关
    git config --global --list  # 查看全局设置相关参数列表
    git config --local --list # 查看本地设置相关参数列表
    git config --system --list # 查看系统配置参数列表
    git config --list  # 查看所有Git的配置(全局+本地+系统)
    

    2.获取帮助【git help】

    git help 命令   # 如:git help init

    3.创建本地仓库【git init】

    git init 仓库名 # 创建一个新的带Git仓库的项目
    git init # 为已存在的项目生成一个Git仓库

    4.添加文件到暂存区/文件跟踪标记【git add】

    可以使用git add 文件名,将工作空间的文件添加到暂存区,或批量添加文件

    git add 文件名 # 将工作区的某个文件添加到暂存区   
    git add -u # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,不处理untracked的文件
    git add -A # 添加所有被tracked文件中被修改或删除的文件信息到暂存区,包括untracked的文件
    git add . # 将当前工作区的所有文件都加入暂存区
    git add -i # 进入交互界面模式,按需添加文件到缓存区

    附:交互界面模式示例

    上图流程:

    1.先在GitForTest的文件夹里创建了两个文件
    2.键入git add -i,进入后,键入4,选择添加untracked的文件
    3.他给我们列出了untracked的文件,然后我们根据序号来添加文件
    4.输入?会弹出相关提示,然后直接回车,结束选择!
    5.然后再次输入git add -i,输入4,可以看到已不存在untacked的文件了!


    5.让Git不Tracked特定文件【.gitignore文件配置】

    将未tracked的文件添加到缓存区后,Git就会开始跟踪这个文件了!
    对于一些比如:自动生成的文件日志临时编译文件等,就
    没必要进行跟踪了,这个时候可以编写.gitignore文件,在里面
    把不需要跟踪的文件或文件夹都写上,git就不会对这些文件进行跟踪!
    另外.gitignore文件与.git文件夹在同级目录下

    如果不想自己写,可以直接到:https://github.com/github/gitignore 复制粘贴!
    也可以自行编写,支持简化了的正则表达式(规范与示例模板摘自:Git王者超神之路)

    • * : 匹配零个或多个任意字符
    • [abc]:只匹配括号内中的任意一个字符
    • [0-9]:- 代表范围,匹配0-9之间的任何字符
    • ?:匹配任意一个字符
    • *:匹配任意的中间目录,例如a/*/z可以匹配:a/z,a/b/z,a/b/c/z等

    示例模板

    # 忽略所有以 .c结尾的文件
    *.c
    
    # 但是 stream.c 会被git追踪
    !stream.c
    
    # 只忽略当前文件夹下的TODO文件, 不包括其他文件夹下的TODO例如: subdir/TODO
    /TODO
    
    # 忽略所有在build文件夹下的文件
    build/
    
    # 忽略 doc/notes.txt, 但不包括多层下.txt例如: doc/server/arch.txt
    doc/*.txt
    
    # 忽略所有在doc目录下的.pdf文件
    doc/**/*.pdf

    !!!特别要注意一点!!!:

    配置.gitignore只对那些没有添加到版本控制系统的文件生效(未Tracked的文件)!

    举个例子:

    有A,B两个文件,你先把他两个add了,然后在.gitignore文件中
    配置了不跟踪这两个文件,但是你会发现根本不会生效。

    git add A
    git add B
    # 配置不跟踪A和B
    git add .gitignore

    所以,最好的做法就是在项目刚开始的时候,先添加.gitignore文件。
    当然,即使是发生了,还是有解决方法的,可以键入下述命令清除标
    记状态,然后先添加.gitignore,再添加文件即可:

    git rm -r --cached . # 清除版本控制标记,.代表所有文件,也可指定具体文件

    还有,如果你用的是IDEA的编辑器的话,可以下一个.ignore的插件,可以手动
    直接勾选不需要跟踪的文件。


    6.将暂存区内容提交到本地仓库【git commit】

    git commit -m "提交说明" # 将暂存区内容提交到本地仓库
    git commit -a -m "提交说明" # 跳过缓存区操作,直接把工作区内容提交到本地仓库

    如果不加-m “提交说明”,git会让用你让默认编辑器(如vi)来编写提交说明,
    可能有些朋友用不惯vi,要么别漏掉-m “提交说明”,要么自己设置编译器:

    git config --global core.edit 喜欢的编辑器

    除此之外,有时可能需要修改上次提交的内容,比如修改提交说明,或者修改文件等:

    # 合并暂存区和最近的一次commit,生成新的commit并替换掉老的
    # 如果缓存区没内容,利用amend可以修改上次commit的提交说明
    # 注:因为amend后生成的commit是一个全新的commit,旧的会被
    # 删除,所以别在公共的commit上使用amend!切记!!!
    
    git commit --amend 
    git commit --amend --no-edit # 沿用上次commit的提交说明

    7.查看工作区与缓存区的状态【git status】

    git status # 查看工作区与暂存区的当前情况
    git status -s # 让结果以更简短的形式输出

    8.差异对比(内容变化)【git diff】

    git diff # 工作区与缓存区的差异
    git diff 分支名 #工作区与某分支的差异,远程分支这样写:remotes/origin/分支名
    git diff HEAD  # 工作区与HEAD指针指向的内容差异
    git diff 提交id 文件路径 # 工作区某文件当前版本与历史版本的差异
    git diff --stage # 工作区文件与上次提交的差异(1.6 版本前用 --cached)
    git diff 版本TAG # 查看从某个版本后都改动内容
    git diff 分支A 分支B # 比较从分支A和分支B的差异(也支持比较两个TAG)
    git diff 分支A...分支B # 比较两分支在分开后各自的改动
    
    # 另外:如果只想统计哪些文件被改动,多少行被改动,可以添加 --stat 参数

    9.查看历史提交记录【git log】

    git log # 查看所有commit记录(SHA-A校验和,作者名称,邮箱,提交时间,提交说明)
    git log -p -次数 # 查看最近多少次的提交记录
    git log --stat # 简略显示每次提交的内容更改
    git log --name-only # 仅显示已修改的文件清单
    git log --name-status # 显示新增,修改,删除的文件清单
    git log --oneline # 让提交记录以精简的一行输出
    git log –graph –all --online # 图形展示分支的合并历史
    git log --author=作者  # 查询作者的提交记录(和grep同时使用要加一个--all--match参数)
    git log --grep=过滤信息 # 列出提交信息中包含过滤信息的提交记录
    git log -S查询内容 # 和--grep类似,S和查询内容间没有空格
    git log fileName # 查看某文件的修改记录,找背锅专用

    除此之外,还可以通过 –pretty 对提交信息进行定制,比如:

    更多规则与定制如下(摘自:Git王者超神之路),或参见:Viewing the Commit History

    format对应的常用占位符:(注:作者是指最后一次修改文件的人,提交者是提交该文件的人)

    占位符 说明 占位符 说明
    %H 提交对象(commit)的完整哈希字串 %h 提交对象的简短哈希字串
    %T 树对象(tree)的完整哈希字串 %t 树对象的简短哈希字串
    %P 父对象(parent)的完整哈希字串 %p 父对象的简短哈希字串
    %an 作者(author)的名字 %ae 作者的电子邮件地址
    %ad 作者修订日期(可以用 –date= 选项定制格式) %ar 按多久以前的方式显示
    %cn 提交者(committer)的名字 %ce 提交者的电子邮件地址
    %cd 提交日期 %cr 提交日期,按多久以前的方式显示
    %s 提交说明

    一些其他操作:

    选项 说明
    -p 按补丁格式显示每个更新之间的差异
    stat 显示每次更新的文件修改统计信息(行数)
    shortstat 只显示 –stat 中最后的行数修改添加移除统计
    name-only 仅在提交信息后显示已修改的文件清单
    name-status 显示新增、修改、删除的文件清单
    abbrev-commit 仅显示 SHA-1 的前几个字符,而非所有的 40 个字符
    relative-date 使用较短的相对时间显示(比如,“2 weeks ago”)
    graph 显示 ASCII 图形表示的分支合并历史
    pretty 格式定制,可选选项有:oneline,short,full,Fullerton和format(后跟指定格式)

    还有一些限制log输出的选项

    选项 说明
    -(n) 仅显示最近的 n 条提交
    since, –after 仅显示指定时间之后的提交。
    until, –before 仅显示指定时间之前的提交。
    author 仅显示指定作者相关的提交。
    committer 仅显示指定提交者相关的提交。
    grep 仅显示含指定关键字的提交
    -S 仅显示添加或移除了某个关键字的提交

    10.查看某行代码是谁写的【git blame】

    git blame 文件名 # 查看某文件的每一行代码的作者,最新commit和提交时间

    Tip:

    如果你用的IDEA系列的编译器,右键行号,选择Annotate也可以实现同样的效果


    11.设置Git命令别名【git config –global alias】

    可以为常见的命令起个简单的别名,就不用每次都敲完整命令,比如可以设置:
    status为st,checkout为co ; commit为ci ; branch为br等

    git config --global alias.st status


    12.为重要的commit打标签【git tag】

    对于某些提交,我们可以为它打上Tag,表示这次提交很重要,
    比如为一些正式发布大版本的commit,打上TAG,当某个版本
    出问题了,通过TAG可以快速找到此次提交,拿到SHA1值,再
    去查找问题,比起一个个commit看,省事很多!

    Git标签分两种:轻量标签附加标签
    前者只是在提交上加个Tag,指向提交的Hash值;
    而后者还会保存打标签者的信息,时间和附加信息;

    git tag 标记内容 # 轻量标签
    git tag -a 标记内容 -m "附加信息" # 附加标签

    如果想为之前的某次commit打TAG的话,可以先找出SHA1值,设置调下述命令:

    git tag -a 标记内容 版本id # 比如:git tag -a v1.1 bcfed96

    默认情况,git push不会把标签推送TAG到远程仓库,如果想推送到服务器,可以:

    git push origin 标记内容 # 推送某标签到
    
    # 删除所有本地仓库中不存在的TAG:
    git push origin --tags 

    另外,可以在新建分支的时候也加上TAG

    git checkout -b 分支名 标记内容

    还可以用show命令查看标签对应的信息

    git show 标记内容

    如果你想删除本地Tag:

    git tag -d 标记内容

    如果是删除远程Tag:

    git push origin --delete tag 标记内容

    13.Git命令自动补全【输命令的时候按两次tab键】


    文件回复/版本回退


    1.文件恢复(未commit)【git checkout】

    如果在工作区直接删除被Git Tracked的文件,暂存区中还会存在该文件,
    此时键入:git status,会是这样:

    Git告诉你工作区的文件被删除了,你可以 删掉暂存区里的文件恢复被删文件

    # 删除暂存区中的文件:
    git rm 文件名
    git commit -m "提交说明"
    
    # 误删恢复文件
    git checkout -- 文件名
    
    # 另外注意:git checkout会抛弃当前工作区的更改!!!不可恢复!!!务必小心!!!
    

    2.文件恢复(已add未commit)【git reset HEAD】

    如果更改后add到了暂存区,想恢复原状,下述指令可以让文件恢复原状:

    git reset HEAD 文件名   
    git checkout 文件名

    3.版本回退(已commit)【git reset –hard】

    文件已经commit了,想恢复成上次commit的版本或者上上次,可以:

    git reset HEAD^ # 恢复成上次提交的版本
    git reset HEAD^^ # 恢复成上上次提交的版本,就是多个^,以此类推或用~次数
    git reset --hard 版本号 # git log查看到的SHA1值,取前七位即可,根据版本号回退

    reset命令其实就是:重置HEAD指针,让其指向另一个commit
    而这个动作可能会对工作区与缓存区造成影响,举个例子

    • 本来的分支线:- A - B - C (HEAD, master)
    • git reset B后:- A - B (HEAD, master)
      解释:看不到C了,但是他还是存在的,可以通过git reset C版本号找回,前提是
      C没有被Git当做垃圾处理掉(一般是30天)。

    reset三个可选参数解析

    • –soft:只是改变HEAD指针指向,缓存区和工作区不变;
    • –mixed:修改HEAD指针指向,暂存区内容丢失,工作区不变;
    • –hard:修改HEAD指针指向,暂存区内容丢失,工作区恢复以前状态;

    4.查看输入指令记录【git reflog】

    Git会记住你输入的每个Git指令,比如上面的git reset 切换成一个旧的
    commit,然后git log后发现新提交的记录没了,想切换回新的那次commit,
    可以先调git reflog 获取新commit的SHA1码,然后git reset 回去。

    git reflog

    注意:这个指令记录不会永久保存!Git会定时清理用不到的对象!!!


    5.撤销某次提交【git revert】

    有时可能我们想撤销某次提交所做的更改,可以使用revert命令

    git revert HEAD # 撤销最近的一个提交
    git revert 版本号 # 撤销某次commit

    不是真的把提交给撤销了,而是生成一个新的提交来覆盖旧的提交,被撤销的提交
    和新的提交记录都会保存!!!不信你再调一次revert HEAD 会发现被撤销的更改
    又变回来了,另外,每次revert后,都需要发起新的commit!
    简单点说,撤销的只是文件变化,提交记录依旧是存在的


    6.查看某次提交修改内容【git show】

    git show 提交id # 查看某次commit的修改内容

    7.查看某个分支的版本号【git rev-parse】

    git rev-parse 分支名 # 查看分支commit的版本号,可以写HEAD

    8.找回丢失对象的最后一点希望【git fsck】

    因为你的某次误操作导致commit丢失,如果git reflog都找不到,你
    可以考虑使用git fsck,找到丢失的对象的版本id,然后恢复即可。

    git fsck --lost-found


    本地分支


    1.分支概念

    提交记录串成的时间线,默认初始创建的分支(时间线) —— master分支
    如果不切换到其他分支上,每次commit生成的快照都会串在这条分支上!
    另外还有个 —— HEAD指针,该指针指向正在工作的本地分支,前面的版
    本回退其实修改的就是这个HEAD指针的指向

    比如:在master分支上执行四次commit,分支的状态图如下

    不难发现这样的规律:

    • 每次commit,master都会向前移动一步,指向最新的提交
    • HEAD则指向正在工作的本地分支,而git reset修改的就是HEAD指针的指向!

    2.创建其他分支的原因

    通过两个场景来体会创建其他分支的必要性

    • 场景一
      项目一般都是一步步迭代升级的,有大版本和小版本的更新:
      大版本一般是改头换面的更新,比如UI大改,架构大改,版本是:
      v2.0.0这样;小版本的更新一般是UI小改,Bug修复优化等,版本是:
      v2.0.11这样;只有一条master分支,意味着:你的分支线会
      非常非常的长,假如你已经发布到了第二个大版本,然后用户反馈
      第一个版本有很严重的BUG,这时候想切回第一个版本改BUG,
      然后改完BUG切回第二个大版本,想想也是够呛的。
      (PS:可能你说我可以对重要的commit打tag,然后找到这个tag
      切回去,当然也行这里是想告诉你引入其他分支会给你带来的便利)
    • 场景二
      只有一个master分支的话,假如某次提交冲突了,而这个冲突很难解决或者
      解决不了, 那么,那个整个开发就卡住在这里了,无法继续向后进行了!

    3.一个最简单实用的分支管理策略

    为了解决只有一个master分支引起的问题,可以引入分支管理,最简单的一种策略如下:

    master分支上开辟一个新的develop分支,然后我们根据功能或者业务,再在develop
    分支上另外开辟其他分支,完成分支上的任务后,再将这个分支合并到develop分支上!
    然后这个功能分支的任务也到此结束,可以删掉,而当发布正式版后,再把develop分支
    合并到master分支上,并打上TAG。

    master与develop分支都作为长期分支,而其他创建的分支作为临时性分支
    简述各个分支的划分:

    • master分支:可直接用于产品发布的代码,就是正式版的代码
    • develop分支:日常开发用的分支,团队中的人都在这个分支上进行开发
    • 临时性分支:根据特定目的开辟的分支,包括功能(feature)分支,或者预发布(release)分支
      又或者是修复bug (fixbug)分支,当完成目的后,把该分支合并到develop分支,
      然后删除 该分支,使得仓库中的常用分支始终只有:master和develop两个长期分支

    4.分支创建与切换【git branch】

    git branch 分支名 # 创建分支
    git branch # 查看本地分支

    比如在master分支上创建develop分支,此时的分支状况如下:

    git checkout 分支名 # 切换分支
    git checkout -b 分支名 # 创建分支同时切换到这个分支

    切换到develop分支后,改点东西,再commit,此时的分支状况如下:

    git checkout master 切回master分支,打开之前修改的文件,发现内容
    并没有发生更改,因为刚刚的更改是在develop上提交的,而master上没有
    变化,此时的分支状况如下:


    5.分支的合并【git merge】 VS 【git rebase】

    Git中,可以使用 git mergegit rebase 两个命令来进行分支的合并

    git merge合并分支

    合并的方式分为两种:快速合并普通合并,两者的区别在于:
    前者合并后看不出曾经做过合并,而后合并后的历史会有分支记录,如图:

    快速合并普通合并

    示例

    快速合并,把develop分支合并到master分支上,来到master分支后,键入下述命令

    git merge develop

    打开文件:

    普通合并,切到develop分支下,修改note_2.txt的内容,再通过下述指令合并分支:
    注:–no-ff参数表示禁用快速合并

    git merge --no-ff -m "合并的信息(TAG)" develop

    分支线情况:

    git reabse合并分支

    rebase(衍合或变基),发现很多所谓的教程把这个东西写得太深奥了,
    其实并没有那么复杂,只是这种合并会使得树整洁,易于跟踪,
    举个简单的例子来对比下,有一个项目由两个人同时开发,
    当前远程仓库的提交记录是这样的:

    然后A和B各自开了一个条分支来完成相应功能,接着他们在自己的
    分支上都做了多次的commit,此时两人的分别分支线是这样的:

      

    A先合并,再到B合并,这里我们假设两人做的是完全不关联的模块,合并没有冲突

    merge合并

    rebase合并

    用法:

    git rebase 想合并到哪个分支的分支名

    6.解决合并冲突

    在我们合并分支的时候,有时会遇到合并冲突,然后合并失败的问题,
    此时需要我们先解决冲突后才能进行合并,个人开发倒很少会遇到,多人
    开发的时候遇到合并冲突则是家常便饭。

    一个最简单的例子,A和B在develop分支上开辟出两个分支来完成相关的
    功能,A做完了,把自己的分支合并到develop分支,此时develop分支向前
    移动了几次commit,接着B也完成了他的功能,想把自己分支合并到develop
    分支,如果改动的文件和和A改动的文件相同的话,此时就会合并失败,
    然后需要处理完冲突,才能够继续合并!简单模拟下这个例子,先试试merge!

    merge分支后处理冲突

    打开冲突文件,然后处理冲突部分,保留什么代码你自己决定,处理完后把
    <<< 和 >>> 这些去掉:

    处理后:

    然后add,然后commit即可,合并结束:

    此时的分支线:

    接着试试

    rebase分支后处理冲突

    重新来一遍,然后把A直接merge到master,再切到B,rebase master,此时出现
    合并冲突,这里有三个可选的操作:

    git rebase --continue # 处理完冲突后,继续处理下一个补丁
    git rebase --abort # 放弃所有的冲突处理,恢复rebase前的情况
    git rebase --skip # 跳过当前的补丁,处理下一个补丁,不建议使用,补丁部分的commit会丢失!

    好的,有三次补丁要处理,一个个来:

    处理后:

    接着git add 添加修改后的文件,git rebase –continue继续处理补丁:

    接着重复之前的过程:

    处理后:

    第三个补丁是与A分支无关联的改动,所以没有冲突,所以也就直接合并了!
    如果合并中途出了什么差错可以git rebase –abort 恢复rebase前的状况!

    最后看下分支线会发现是一条直线,这也是用rebase合并分支的优点:

    附上栗子,可以自己试试GitTest.7z


    7.删除分支

    对于合并完的分支,基本都没什么作用了,可以使用下述命令删除:

    git branch -d 分支名 # 删除分支,分支上有未提交更改是不能删除的
    git branch -D 分支名 # 强行删除分支,尽管这个分支上有未提交的更改

    8.恢复误删分支

    两步,找出被删除分支的最新commit的版本号,然后恢复分支

    git log --branches="被删除的分支名" # 找到被删分支最新的commitb版本号
    git branch 分支名 版本号(前七位即可) # 恢复被删分支

    9.切换分支时保存未commit的更改【git stash】

    有时我们可能在某个分支上正编写着代码,然后有一些突发的情况,需要
    我们暂时切换到其他分支上,比如要紧急修复bug,或者切换分支给同事
    review代码,此时如果直接切换分支是会提示切换失败的,因为这个分支
    上做的更改还没有提交,你可以直接add后commit,然后再切换,不过我们
    习惯写完某个功能再提交,我们想:

    先暂存这个分支上的改动,切去其他分支上搞完事,然后回来继续
    继续在之前的改动上写代码。

    那么可以使用:

    git stash # 保存当前的改动

    然后放心的切换分支,然后再切换回来,接着使用:

    git stash apply # 恢复保存改动

    另外有一点一定要注意!!!可以stash多个改动!!如果你切换
    到另一个分支又stash了,然后切换回来stash apply是恢复成另一个
    分支的stash!!!

    如果你这样stash了多次的话,我建议你先键入:

    git stash list # 查看stash列表

    找到自己想恢复的那个

    比如我这里恢复的应该是netword上的stash,而第一个stash是devlop上的
    直接git stash apply恢复的就是这个,然而恢复的应该是network的那个stash:

    git stash apply stash@{1}

    就是这样,按自己需要恢复即可!


    10.分支重命名

    git branch -m 老分支名 新分支名 # 分支重命名

    远程仓库与远程分支


    1.远程仓库简述

    用于代码托管,可以自己搭建远程仓库,或者选择专业的代码托管平台:
    自己搭建的好处有:可控,内网安全,可以做一些定制,比如集成编译,IM等,
    当然,肯定是需要一些学习成本的,(PS:我厂就是自己搭的Gitlab,自己配置
    还是比较麻烦的,简单点的可以试试 Gogs)

    常见的代码托管平台(自己搜关键字去~):

    Github,Git@OSC,GitCafe,GitLab,coding.net,gitc,BitBucket,Geakit,Douban CODE


    2.推送本地仓库到远程仓库【git push】

    首先建立好与本地仓库同名的远程仓库,然后复制下远程仓库的地址,比如:

    键入下述命令关联本地与远程仓库

    git remote add origin 远程仓库地址 

    可以键入下述命令可查看远程仓库状况

    接着把本地仓库推送到远程仓库,这里的 -u参数 作为第一次提交使用,
    作用是把本地master分支和远程master分支关联起来(设置默认远程主机),
    后续提交不需要这个参数!

    git push -u origin master

    另外,如果想修改远程仓库地址,可键入:

    git remote set-url origin 远程仓库地址
    
    # 也可以先删除origin后再添加
    
    git remote rm origin    # 删除仓库关联
    git remote add origin 远程仓库地址 # 添加仓库关联

    或直接修改.git文件夹中的config文件,直接替换圈住位置

    还要说明一点,origin 并不是固定的东西,只是后面仓库地址的一个 别名!!
    可以写成其他的东西,然后你也可以设置多个仓库关联,用不同的别名标志,比如:

    git remote add github https://github.com/coder-pig/SimpleTea.git
    git remote add osc git@git.oschina.net:coder-pig/SimpleTea.git

    3.克隆远程仓库【git clone】

    把项目推送到远程仓库后,其他开发者就可以把项目clone到本地

    git clone 仓库地址 # 克隆项目到当前文件夹下
    git clone 仓库地址 目录名 # 克隆项目到特定目录下

    4.同步远程仓库更新【git fetch】VS 【git pull】

    关于获取远程服务器更新的方式有两种,他们分别是fetch和pull,
    尽管都可以获取远程服务器更新,但是两者却又是不一样的。

    git fetch

    仅仅只是从远处服务器获取到最新版本到本地,假如你不去合并(merge)
    的话,本地工作空间是不会发生变化的!比如:
    我们在Github上创建一个README.md文件,然后调 git fetch 去获取远程
    仓库的更新。

    git pull

    一步到位,或者说:pull = fetch + merge,比如:同样修改Github上的
    README.md 文件,然后git pull 同步远程仓库的更新

    区别显而易见,实际开发中,使用git fetch会更安全一些,毕竟merge的时候
    我们可以查看更新的情况,再决定是否进行合并,当然看实际需要吧!


    5.推送本地分支到远程仓库

    按照前面所讲,在本地开辟分支来完成某些工作,本地提交了多次后,
    你想把分支推送到远程仓库,此时远程仓库并没有这个分支,你可以:

    git push origin 分支名 # 推送本地分支的内容到远程分支

    6.查看远程分支

    git branch -r # 查看所有分支

    7.拉取远程分支到本地仓库

    git checkout -b 本地分支 远程分支 # 会在本地新建分支,并自动切换到该分支
    git fetch origin 远程分支:本地分支 # 会在本地新建分支,但不会自动切换,还需checkout
    git branch --set-upstream 本地分支 远程分支 # 建立本地分支与远程分支的链接

    8.删除远程分支

    git push origin :分支名 

    9.重命名远程分支

    先删除远程分支,然后重命名本地分支,接着再Push到远程仓库


    10.为项目添加SSH Key免去提交输入账号密码的麻烦

    不知道细心的你有没有发现,仓库地址除了Https外,还有一个SSH,
    这里我们简单介绍下两者的区别,第一点:使用Https url可以任意克隆
    Github上的项目;而是用SSH url克隆的话,你必须是项目的拥有者或
    管理员,而且还要添加SSH Key,否则会无法克隆。还有一点是,
    Https每次push都需要输入用户名和密码,而使用SSH则不需要输入
    用户名如果配置SSH Key时设置了密码,则需要输入密码,否则直接
    git push就可以了!

    另外,SSH,Secure shell(安全外壳协议),专为远程登陆会话
    与其他网络服务提供安全性的协议,而SSH传输的数据是可以经过压缩的,
    可以加快传输的速度,出于安全性与速度,我们优先考虑使用SSH协议,
    而SSH的安全验证规则又分为基于密码基于密钥两种!
    我们这里用的是基于第二种的,即在本地创建一对密钥,
    公钥(id_rsa.pub)私钥(id_rsa),然后把公钥的内容贴到
    Github账号的ssh keys中,这样就建立了本地和远程的认证关系,
    当我们再push到远程仓库,会将你本地的公共密钥与服务器的进行匹配,
    如果一致验证通过直接推送更新!

    下面我们来建立ssh key,首先来到电脑的根目录下,这里假定我们没
    创建过SSH key:

    执行完ssh-keygen那个指令后,后面依次要你输入文件名,
    直接回车会生成两个默认的秘钥文件,接着提示输入密码,
    直接回车,如果这里你输入密码了的话,那么push的时候
    你还是需要输入密码,接着又输多一次密码,同样回车,
    然后出现最下面的这串东西就说明ssh key已经创建成功了!

    我们接着可以用编辑器打开id_rsa.pub文件或者键入:

    clip <id_rsa.pub

    复制文件内容,然后打开Github,点击你的头像,选择:Settings
    然后点击左侧SSH Keys,然后New SSH Key

    然后Github会给你发来一个提示创建了一个新ssh key的邮件,
    无视就好,接下来我们可以键入:ssh -T git@github.com
    然后如果你上面设置过密码则需要输入密码,
    否则直接输入yes然后一直按回车就好!,最后出现Hi xxx那句话
    就说明ssh key配置成功了!

    PS:其他远程仓库配置方法与此类同,
    内容参考自:https://help.github.com/articles/generating-an-ssh-key/


    附1:Github客户端

    其实,安装好Git后,就一有一个GitGui的东东了,就可以直接
    用有用户界面的Git来做版本管理的工作了,而Github客户端则是
    Github给我们提供的一个专门用来管理Github项目的一个工具而已。
    比如,假如你装了Github客户端,在Clone项目的时候,你只需点击:

    就能直接把项目clone下来,就是一些Git操作的图形化罢了,首先来到下面的链接
    下载Github客户端:https://desktop.github.com/
    文件很小,后面点击运行文件后,他还要在线下载安装,100多m,
    然后傻瓜式安装,安装完成后,会自动打开Github客户端,然后
    使用你的Github账号登陆,接着他会默认为你创建SSH Key信息,
    接着的你自己摸索了!

    这里另外补充一点,就是win 8.1装Github客户端的问题,
    昨晚安装的时候一直报这个错误:

    直接,win + x,选择”命令行提示符(管理员)“,执行以下下面的这个指令:

    %SYSTEMROOT%\SYSTEM32\REGSVR32.EXE %SYSTEMROOT%\SYSTEM32\WUAUENG.DLL

    然后再点击Github的安装程序,等待安装完成即可,下载并不需梯子。


    附2:删除Git仓库

    点击进入你的仓库,点击Setting,拉到最后:

    点击Delete this repository

    弹出的对话框中输入要删除的仓库名称,接着点击删除


    附3:为开源项目贡献代码

    你可以Clone别人的开源项目,在看别人代码的时候,你觉得作者有
    某些地方写得不好,写错,或者你有更好的想法,你在本地修改后,
    想把修改push推送到开源项目上,想法很好,但是你不是项目的拥
    有着和参与者,是无法推送更改的!!!这样是为了
    避免熊孩子,毕竟熊孩子无处不在,参与开源项目的方法有两种:

    第一种方法
    是让作者把你加为写作者,添加协作者流程:点击仓库的Settings
    –>Collaborators然后输入想添加的人的用户名或者邮箱,点击
    添加即可。

    第二种方法
    点击Fork按钮,把这个项目fork到自己的账号下,然后Clone
    到本地,然后做你想做的修改,commit提交,然后push到自己账
    号里的仓库,然后打开开源项目,点击,然后新建一个
    pull request,接着设置自己的仓库为源仓库,设置源分支
    目标仓库目标分支,然后还有pull request的标题和描述信息,
    填写完毕后,确定,这个时候开源项目的作者就会收到一个pull
    request的请求,由他来进行审核,作者审查完代码觉得没问题
    的话,他可以点击一下merge按钮即可将这个pull request合并
    到自己的项目中,假如作者发现了你代码中还有些bug,他可以
    通过Pull Request跟你说明,要修复了xxBUG才允许合并,那么
    你再修改下BUG,提交,更改后的提交会进入Pull Request,
    然后作者再审核这样!

    PS:假如作者不关闭或者merge你的这个Pull Request,你可以一直
    commit骚扰主项目…( ╯□╰ )


    Git工作流

    关于Git工作流,看到一篇图文并茂很好的文章,就不重复造轮子了,
    此处只是做下对应工作流的简述,详情见:Git Workflows and Tutorials


    1.集中式工作流

    类似于SVN,不过只有一条master分支,然后一群人就在这条分支上嗨,比如有小A和小B:
    (冲突解决参照上面的套路)

    • 1.项目管理者初始化仓库,然后推到远程仓库
    • 2.其他人克隆远程仓库项目到本地
    • 3.小A和小B完成各自的工作
    • 4.小A先完成了,git push origin master 把代码推送到远程仓库
    • 5.小B后完成了,此时推送代码到远程仓库,出现文件修改冲突
    • 6.小B需要先解决冲突,git pull –rebase origin master,然后rebase慢慢玩
    • 7.小B把冲突解决后,git push origin master 把代码推送到远程仓库

    2.功能分支工作流

    和集中式分部流相比只是分支再不是只有master,而是根据功能开辟新的分支而已,示例:
    注:这里的仓库管理者是拥有仓库管理权限的人

    • 1.小A要开发新功能,git branch -b new-feature 开辟新分支
    • 2.小A在new-feature上新功能相关的编写,他可以这个分支推到远程仓库
    • 3.功能完成后,发起请求pull request(合并请求),把new-feature合并到master分支
    • 4.仓库管理员可以看到小A的更改,可以进行一些评注,让小A做某些更改,
      然后再发起pull request,或者把pull request拉到本地自行修改。
    • 5.仓库管理员觉得可以了,合并分支到master上,然后把new-feature分支删掉

    3.Gitflow工作流

    其实就是功能分支工作流做了一些规范而已,大概流程参见上面Git分支里的:
    一个最简单实用的分支管理策略。


    4.Forking工作流

    分布式工作流,每个开发者都拥有自己独立的仓库,和上面的附3:为开源项目贡献代码
    套路类似,把项目fork到自己的远程仓库,完成相应更改,然后pull request到源仓库,
    源仓库管理者可以决定是否合并。


    5.Pull Request工作流

    和Forking工作流类似,Pull Requests是Bitbucket上方便开发者之间协作的功能


    查缺补漏

    一些高级技巧,工具,插件安利


    1.巨好用的Git图形化工具SourceTree

    命令行虽酷炫可装逼,但是有时用图形化工具还是能提高我们不少效率的,
    如题,SourceTree,官网下载地址:https://www.sourcetreeapp.com/


    2.把提交的commit从一个分支放到另一个分支【git cherry-pick】

    有时你可能需要把某个分支上的commit放到另一个分支上,这个时候可以
    使用cherry-pick,比如有下面这样两个分支:

    master分支:A -> B -> C
    feature分支:a -> b

    现在想把feature上的b,放到master的C后,可以这样:

    • Step 1:切换到feature分支上,git log拿到b commit的版本号(SHA1)
    • Step 2:切换到master分支,键入:git cherry-pick 版本号

    出现上面这种情况的话说明出现冲突了,处理冲突后,git add 和 git commit 走一波
    即可。


    问题解决

    1.fatal: refusing to merge unrelated histories

    问题描述:在Github上新建了一个仓库,里面带有一个licence文件,然后本地
    本地项目想推到这个远程仓库上,git remote 设置了远程仓库后,push提示先pull,
    pull的时候就报这个错了,解决方法如下:

    git pull origin master --allow-unrelated-histories

    待续…(最近更新:2017.10.26)

    编辑日志:

    • 2017.5.3: 添加.gitignore注意事项
    • 2017.9.5: 排版与内容优化,勘误,新增查缺补漏
    • 2017.10.26:新增问题解决模块
    展开全文
  • git&github快速入门

    2019-09-27 01:14:22
    在开发中,这是刚需,必须允许可以很容易对产品的版本进行任意回滚,版本控制工具实现这个功能的原理简单来讲,就是你每修改一次代码,它就帮你做一次快照 协作开发: 一个复杂点的软件,往往不是一个开发人员可以...

    git功能:

    版本管理:

    在开发中,这是刚需,必须允许可以很容易对产品的版本进行任意回滚,版本控制工具实现这个功能的原理简单来讲,就是你每修改一次代码,它就帮你做一次快照

    协作开发:

    一个复杂点的软件,往往不是一个开发人员可以搞定的,公司为加快产品开发速度,会招聘一堆跟你一样的开发人员开发这个产品,拿微信来举例,现在假设3个人一起开发微信,A开发联系人功能,B开发发文字、图片、语音通讯功能,C开发视频通话功能, B和C的功能都是要基于通讯录的,你说简单,直接把A开发的代码copy过来,在它的基础上开发就好了,可以,但是你在他的代码基础上开发了2周后,这期间A没闲着,对通讯录代码作了更新,此时怎么办?你和他的代码不一致了,此时我们知道,你肯定要再把A的新代码拿过来替换掉你手上的旧通讯录功能代码, 现在人少,3个人之间沟通很简单,但想想,如果团队变成30个人呢?来回这样copy代码,很快就乱了, 所以此时亟需一个工具,能确保一直存储最新的代码库,所有人的代码应该和最新的代码库保持一致

    常见版本管理工具介绍:

    1、VSS-- Visual Source Safe
    此工具是Microsoft提供的,是使用的相当普遍的工具之一,他可以与VS.net进行无缝集成,成为了独立开发人员和小型开发团队所适合的工具,基本上Window平台上开发的中小型企业,当规模较大后,其性能通常是无法忍受的,对分支与并行开发支持的比较有限。

    2、CVS--Concurrent Versions System,
    此工具是一个开源工具,与后面提到的SVN是同一个厂家:Collab.Net提供的。
    CVS是源于unix的版本控制工具,对于CVS的安装和使用最好对unix的系统有所了解能更容易学习,CVS的服务器管理需要进行各种命令行操作。目前,CVS的客户端有winCVS的图形化界面,服务器端也有CVSNT的版本,易用性正在提高。
    此工具是相当著名,使用得相当广泛的版本控制工具之一,使用成熟的“Copy-Modify-Merge"开发模型,可以大大的提高开发效率,适合于项目比较大,产品发布频繁,分支活动频繁的中大型项目。

    3、SVN --CollabNet Subversion
    此工具是在CVS 的基础上,由CollabNet提供开发的,也是开源工具,应用比较广泛。
    他修正cvs的一些局限性,适用范围同cvs,目前有一些基于SVN的第三方工具,如TortoiseSVN,是其客户端程序,使用的也相当广泛。在权限管理,分支合并等方面做的很出色,他可以与Apache集成在一起进行用户认证。
    不过在权限管理方面目前还没有个很好用的界面化工具,SVNManger对于已经使用SVN进行配置的项目来说,基本上是无法应用的,但对于从头开始的项目是可以的,功能比较强大,但是搭建svnManger比较麻烦。
    是一个跨平台的软件,支持大多数常见的操作系统。作为一个开源的版本控制系统,Subversion 管理着随时间改变的数据。 这些数据放置在一个中央资料档案库中。 这个档案库很像一个普通的文件服务器, 不过它会记住每一次文件的变动。 这样你就可以把档案恢复到旧的版本, 或是浏览文件的变动历史。Subversion 是一个通用的系统, 可用来管理任何类型的文件, 其中包括了程序源码。


    4. GIT
    因为最初是从Linux起家的,非常依赖文件系统的一些特性,这些在 Linux 下表现的很好,而 Windows 下特别糟糕Git 中文教程
    Git是一个开源的分布式版本控制系统,用以有效、高速的处理从很小到非常大的项目版本管理.
    Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。
    Torvalds 开始着手开发 Git 是为了作为一种过渡方案来替代 BitKeeper,后者之前一直是 Linux 内核开发人员在全球使用的主要源代码工具。开放源码社区中的有些人觉得 BitKeeper 的许可证并不适合开放源码社区的工作,因此 Torvalds 决定着手研究许可证更为灵活的版本控制系统。尽管最初 Git 的开发是为了辅助 Linux 内核开发的过程,但是我们已经发现在很多其他自由软件项目中也使用了 Git。例如 最近就迁移到 Git 上来了,很多 Freedesktop 的项目也迁移到了 Git 上。

    5、BitKeeper
    是由BitMover公司提供的,BitKeeper自称是“分布式”可扩缩SCM系统。
    不是采用C/S结构,而是采用P2P结构来实现的,同样支持变更任务,所有变更集的操作都是原子的,与svn,cvs一致。

     

    github介绍:

    很多人都知道,Linus在1991年创建了开源的Linux,从此,Linux系统不断发展,已经成为最大的服务器系统软件了。

    Linus虽然创建了Linux,但Linux的壮大是靠全世界热心的志愿者参与的,这么多人在世界各地为Linux编写代码,那Linux的代码是如何管理的呢?

    事实是,在2002年以前,世界各地的志愿者把源代码文件通过diff的方式发给Linus,然后由Linus本人通过手工方式合并代码!

    你也许会想,为什么Linus不把Linux代码放到版本控制系统里呢?不是有CVS、SVN这些免费的版本控制系统吗?因为Linus坚定地反对CVS和SVN,这些集中式的版本控制系统不但速度慢,而且必须联网才能使用。有一些商用的版本控制系统,虽然比CVS、SVN好用,但那是付费的,和Linux的开源精神不符。

    不过,到了2002年,Linux系统已经发展了十年了,代码库之大让Linus很难继续通过手工方式管理了,社区的弟兄们也对这种方式表达了强烈不满,于是Linus选择了一个商业的版本控制系统BitKeeper,BitKeeper的东家BitMover公司出于人道主义精神,授权Linux社区免费使用这个版本控制系统。

    安定团结的大好局面在2005年就被打破了,原因是Linux社区牛人聚集,不免沾染了一些梁山好汉的江湖习气。开发Samba的Andrew试图破解BitKeeper的协议(这么干的其实也不只他一个),被BitMover公司发现了(监控工作做得不错!),于是BitMover公司怒了,要收回Linux社区的免费使用权。

    Linus可以向BitMover公司道个歉,保证以后严格管教弟兄们,嗯,这是不可能的。实际情况是这样的:

    Linus花了两周时间自己用C写了一个分布式版本控制系统,这就是Git!一个月之内,Linux系统的源码已经由Git管理了!牛是怎么定义的呢?大家可以体会一下。

    Git迅速成为最流行的分布式版本控制系统,尤其是2008年,GitHub网站上线了(github是一个基于git的代码托管平台,付费用户可以建私人仓库,我们一般的免费用户只能使用公共仓库,也就是代码要公开。),它为开源项目免费提供Git存储,无数开源项目开始迁移至GitHub,包括jQuery,PHP,Ruby等等。

    历史就是这么偶然,如果不是当年BitMover公司威胁Linux社区,可能现在我们就没有免费而超级好用的Git了。

     

    今天,GitHub已是:

    • 一个拥有143万开发者的社区。其中不乏Linux发明者Torvalds这样的顶级黑客,以及Rails创始人DHH这样的年轻极客。
    • 这个星球上最流行的开源托管服务。目前已托管431万git项目,不仅越来越多知名开源项目迁入GitHub,比如Ruby on Rails、jQuery、Ruby、Erlang/OTP;近三年流行的开源库往往在GitHub首发,例如:BootStrapNode.jsCoffeScript等。
    • alexa全球排名414的网站

    git安装

    在Linux上安装Git

    首先,你可以试着输入git,看看系统有没有安装Git:

    1 $ git
    2 The program 'git' is currently not installed. You can install it by typing:
    3 sudo apt-get install git

    像上面的命令,有很多Linux会友好地告诉你Git没有安装,还会告诉你如何安装Git。

    如果你碰巧用Debian或Ubuntu Linux,通过一条sudo apt-get install git就可以直接完成Git的安装,非常简单。

     

    版本库创建

    什么是版本库呢?版本库又名仓库,英文名repository,你可以简单理解成一个目录,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。

    所以,创建一个版本库非常简单,首先,选择一个合适的地方,创建一个空目录:

    1 $ mkdir git_trainning
    2 $ cd git_trainning/
    3  
    4 $ git init
    5 Initialized empty Git repository in /Users/alex/git_trainning/.git/

    瞬间Git就把仓库建好了,而且告诉你是一个空的仓库(empty Git repository),细心的读者可以发现当前目录下多了一个.git的目录,这个目录是Git来跟踪管理版本库的,没事千万不要手动修改这个目录里面的文件,不然改乱了,就把Git仓库给破坏了。

    如果你没有看到.git目录,那是因为这个目录默认是隐藏的,用ls -ah命令就可以看见

     

    把文件添加到版本库

    首先这里再明确一下,所有的版本控制系统,其实只能跟踪文本文件的改动,比如TXT文件,网页,所有的程序代码等等,Git也不例外。版本控制系统可以告诉你每次的改动,比如在第5行加了一个单词“Linux”,在第8行删了一个单词“Windows”。而图片、视频这些二进制文件,虽然也能由版本控制系统管理,但没法跟踪文件的变化,只能把二进制文件每次改动串起来,也就是只知道图片从100KB改成了120KB,但到底改了啥,版本控制系统不知道,也没法知道。

    不幸的是,Microsoft的Word格式是二进制格式,因此,版本控制系统是没法跟踪Word文件的改动的,前面我们举的例子只是为了演示,如果要真正使用版本控制系统,就要以纯文本方式编写文件。

    因为文本是有编码的,比如中文有常用的GBK编码,日文有Shift_JIS编码,如果没有历史遗留问题,强烈建议使用标准的UTF-8编码,所有语言使用同一种编码,既没有冲突,又被所有平台所支持。

    言归正传,现在我们编写一个first_git_file.txt文件,内容如下:

    $ vim first_git_file.txt
     
    first time using git, excited!

    一定要放到git_trainning目录下(子目录也行),因为这是一个Git仓库,放到其他地方Git再厉害也找不到这个文件。

    和把大象放到冰箱需要3步相比,把一个文件放到Git仓库只需要两步。

    第一步,用命令git add告诉Git,把文件添加到仓库:

    1 $ git add first_git_file.txt

    执行上面的命令,没有任何显示,说明添加成功。

    第二步,用命令git commit告诉Git,把文件提交到仓库:  

     1 $ git commit -m "commit my first git file"
     2  
     3 [master (root-commit) 621e6e4] commit my first git file
     4  Committer: Alex Li <alex@alexs-macbook-pro.local>
     5 Your name and email address were configured automatically based
     6 on your username and hostname. Please check that they are accurate.
     7 You can suppress this message by setting them explicitly. Run the
     8 following command and follow the instructions in your editor to edit
     9 your configuration file:
    10  
    11     git config --global --edit
    12  
    13 After doing this, you may fix the identity used for this commit with:
    14  
    15     git commit --amend --reset-author
    16  
    17  1 file changed, 2 insertions(+)
    18  create mode 100644 first_git_file.txt
    19 </alex@alexs-macbook-pro.local>

    中间红色部分的意思是,你在往git库里提交代码时,你需要告诉git你是谁,这样git就会纪录下来是谁改的代码,其实就是为了日后查询方便,你只需要提供一个名字和邮件地址就可以,这里我的git直接通过主机名自己创建了一个,但你可以通过git config --global --edit修改

     

    简单解释一下git commit命令,-m后面输入的是本次提交的说明,可以输入任意内容,当然最好是有意义的,这样你就能从历史记录里方便地找到改动记录。

    嫌麻烦不想输入-m "xxx"行不行?确实有办法可以这么干,但是强烈不建议你这么干,因为输入说明对自己对别人阅读都很重要。

    为什么Git添加文件需要addcommit一共两步呢?因为commit可以一次提交很多文件,所以你可以多次add不同的文件,比如:

    $ git add file1.txt
    $ git add file2.txt file3.txt
    $ git commit -m "add 3 files."

     

    代码回滚

    代码修改并提交  

    我们已经成功地添加并提交了一个first_git_file.txt文件,现在,是时候继续工作了,于是,我们继续修改first_git_file.txt文件,改成如下内容:

    First time using git, excited! update ...
    insert line here...

    运行git status命令看看结果:

    1 $ git status
    2 On branch master
    3 Changes not staged for commit:
    4   (use "git add <file>..." to update what will be committed)
    5   (use "git checkout -- <file>..." to discard changes in working directory)
    6  
    7     modified:   first_git_file.txt
    8  
    9 no changes added to commit (use "git add" and/or "git commit -a")

    虽然Git告诉我们first_git_file.txt被修改了,但如果能看看具体修改了什么内容,自然是很好的。比如你休假两周从国外回来,第一天上班时,已经记不清上次怎么修改的readme.txt,所以,需要用git diff这个命令看看:

    1 $ git diff first_git_file.txt
    2 diff --git a/first_git_file.txt b/first_git_file.txt
    3 index 2d13c2c..248d853 100644
    4 --- a/first_git_file.txt
    5 +++ b/first_git_file.txt
    6 @@ -1,3 +1,4 @@
    7 -first time using git, excited!
    8 +First time using git, excited! update ...
    9  insert line here...

    输出中+号绿色显示的就是修改或新增的内容,-号红色显示的就是去掉或被修改的内容

    知道了对first_git_file.txt 作了什么修改后,再把它提交到仓库就放心多了,提交修改和提交新文件是一样的两步,第一步是git add

    1 $ git add . # .  代表把当前目录下所有改动的文件都提交到代码库
    2 Alexs-MacBook-Pro:git_trainning alex$ git commit -m "commit changes"
    3 [master 50ad6b5] commit changes
    4  Committer: Alex Li <alex@Alexs-MacBook-Pro.local>
    5  1 file changed, 1 insertion(+)

    提交后,我们再用git status命令看看仓库的当前状态:

    1 $ git status
    2 # On branch master
    3 nothing to commit (working directory clean)

    Git告诉我们当前没有需要提交的修改,而且,工作目录是干净(working directory clean)的。

     

    代码回滚:

    现在,你已经学会了修改文件,然后把修改提交到Git版本库,现在,再练习一次,修改first_git_file.txtt文件如下:

    1 First time using git, excited! update ...
    2 insert line here..改之前的.
    3 第一次用git哈哈
    4 insert line again haha...
    5 加点新内容 

    然后尝试提交:

    1 $ git add first_git_file.txt
    2 $ git commit -m "add new content"
    3 [master 4459657] add new content
    4  Committer: Alex Li <alex@Alexs-MacBook-Pro.local>
    5  1 file changed, 2 insertions(+), 1 deletion(-)

    像这样,你不断对文件进行修改,然后不断提交修改到版本库里,就好比玩RPG游戏时,每通过一关就会自动把游戏状态存盘,如果某一关没过去,你还可以选择读取前一关的状态。有些时候,在打Boss之前,你会手动存盘,以便万一打Boss失败了,可以从最近的地方重新开始。Git也是一样,每当你觉得文件修改到一定程度的时候,就可以“保存一个快照”,这个快照在Git中被称为commit。一旦你把文件改乱了,或者误删了文件,还可以从最近的一个commit恢复,然后继续工作,而不是把几个月的工作成果全部丢失。

    现在,我们回顾一下first_git_file.txt文件一共有几个版本被提交到Git仓库里了: 

    版本1

    1 first time using git, excited!
    2 第一次用git哈哈

    版本2

    1 first time using git, excited!
    2 insert line here...
    3 第一次用git哈哈

    版本3

    1 first time using git, excited!
    2 insert line here...
    3 第一次用git哈哈
    4 insert line again haha...

    版本4

    First time using git, excited! update ...
    insert line here..改之前的.
    第一次用git哈哈
    insert line again haha...
    加点新内容

    当然了,在实际工作中,我们脑子里怎么可能记得一个几千行的文件每次都改了什么内容,不然要版本控制系统干什么。版本控制系统肯定有某个命令可以告诉我们历史记录,在Git中,我们用git log命令查看:

     1 $ git log
     2 commit 445965781d1fd0d91e76d120450dd18fd06c7489
     3 Author: Alex Li <alex@Alexs-MacBook-Pro.local>
     4 Date:   Tue Oct 4 18:44:29 2016 +0800
     5  
     6     add new content
     7  
     8 commit be02137bb2f54bbef0c2e99202281b3966251952
     9 Author: Alex Li <alex@Alexs-MacBook-Pro.local>
    10 Date:   Tue Oct 4 17:55:16 2016 +0800
    11  
    12     update again
    13  
    14 commit 50ad6b526810bb7ccfea430663757ba2337b9816
    15 Author: Alex Li <alex@Alexs-MacBook-Pro.local>
    16 Date:   Tue Oct 4 17:46:51 2016 +0800
    17  
    18     commit changes
    19  
    20 commit 621e6e44d04fa6a1cdc37826f01efa61b451abd1
    21 Author: Alex Li <alex@Alexs-MacBook-Pro.local>
    22 Date:   Tue Oct 4 17:42:50 2016 +0800
    23  
    24     commit my first git file

    git log命令显示从最近到最远的提交日志,我们可以看到4次提交,最近的一次是add new content,上一次是update again,最早的一次是commit my first git file。 如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline参数:

    1 $ git log --pretty=oneline
    2 445965781d1fd0d91e76d120450dd18fd06c7489 add new content
    3 be02137bb2f54bbef0c2e99202281b3966251952 update again
    4 50ad6b526810bb7ccfea430663757ba2337b9816 commit changes
    5 621e6e44d04fa6a1cdc37826f01efa61b451abd1 commit my first git file

    git操作总结:

    初始化 git init 

    git reflog 查看所有的操作记录

    回滚到上一个版本 git reset --hard HEAD^

    回滚到知道版本 git reset --hard 版本号

    查看当前的代码状态 git status

    把代码从暂存区回滚到工作区 git checkout

     

    工作区和暂存区

    Git和其他版本控制系统如SVN的一个不同之处就是有暂存区的概念。

    先来看名词解释。

    工作区(Working Directory

    就是你在电脑里能看到的目录,比如我的git_trainning文件夹就是一个工作区:

    1 $ ls git_trainning/
    2 first_git_file.txt

    版本库(Repository)

    工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。

    Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD

    前面讲了我们把文件往Git版本库里添加的时候,是分两步执行的:

    第一步是用git add把文件添加进去,实际上就是把文件修改添加到暂存区;

    第二步是用git commit提交更改,实际上就是把暂存区的所有内容提交到当前分支。

    因为我们创建Git版本库时,Git自动为我们创建了唯一一个master分支,所以,现在,git commit就是往master分支上提交更改。

    你可以简单理解为,需要提交的文件修改通通放到暂存区,然后,一次性提交暂存区的所有修改。

    俗话说,实践出真知。现在,我们再练习一遍,先对first_git_file.txt做个修改,比如加上一行内容:

    1 First time using git, excited! update ...
    2 insert line here..改之前的.
    3 第一次用git哈哈
    4 insert line again haha...
    5 加点新内容
    6 update v5

    然后,在工作区新增一个readme.md文本文件(内容随便写)。

    先用git status查看一下状态:

     1 $ git status
     2 On branch master
     3 Changes not staged for commit:
     4   (use "git add <file>..." to update what will be committed)
     5   (use "git checkout -- <file>..." to discard changes in working directory)
     6  
     7     modified:   first_git_file.txt
     8  
     9 Untracked files:
    10   (use "git add <file>..." to include in what will be committed)
    11  
    12     readme.md
    13  
    14 no changes added to commit (use "git add" and/or "git commit -a")

    Git非常清楚地告诉我们,first_git_file.txt被修改了,而readme.md还从来没有被添加过,所以它的状态是Untracked

    现在,使用命令git add . ,再用git status再查看一下:

    1 $ git add .
    2 $ git status
    3 On branch master
    4 Changes to be committed:
    5   (use "git reset HEAD <file>..." to unstage)
    6  
    7     modified:   first_git_file.txt
    8     new file:   readme.md
    9 </file>

    现在,暂存区的状态就变成这样了:

     

    所以,git add命令实际上就是把要提交的所有修改放到暂存区(Stage),然后,执行git commit就可以一次性把暂存区的所有修改提交到分支。

    1 $ git commit -m "知道暂存区stage的意思了"
    2 [master 9d65cb2] 知道暂存区stage的意思了
    3  2 files changed, 2 insertions(+)
    4  create mode 100644 readme.md

    一旦提交后,如果你又没有对工作区做任何修改,那么工作区就是“干净”的:

    1 $ git status
    2 On branch master
    3 nothing to commit, working directory clean

    现在版本库变成了这样,暂存区就没有任何内容了:

     

    暂存区是Git非常重要的概念,弄明白了暂存区,就弄明白了Git的很多操作到底干了什么。

     

    撤销修改 

    自然,你是不会犯错的。不过现在是凌晨两点,你正在赶一份工作报告,你在readme.md中添加了一行:

    1 #git study repo
    2 git is great
    3 but my stupid boss still prefers SVN

    在你准备提交前,一杯咖啡起了作用,你猛然发现了“stupid boss”可能会让你丢掉这个月的奖金!

    既然错误发现得很及时,就可以很容易地纠正它。你可以删掉最后一行,手动把文件恢复到上一个版本的状态。如果用git status查看一下:

     1 git status
     2 On branch master
     3 Changes not staged for commit:
     4   (use "git add <file>..." to update what will be committed)
     5   (use "git checkout -- <file>..." to discard changes in working directory)
     6  
     7     modified:   readme.md
     8  
     9 no changes added to commit (use "git add" and/or "git commit -a")
    10 </file></file>

    你可以发现,Git会告诉你,git checkout -- file可以丢弃工作区的修改:

    1 $ git checkout -- readme.md
    2  
    3 $ more readme.md
    4 #git study repo

    你刚才添加的2行骂老板的话就被撤销了,

    命令git checkout -- readme.md意思就是,把readme.md文件在工作区的修改全部撤销,这里有两种情况:

    一种是readme.md自修改后还没有被放到暂存区,现在,撤销修改就回到和版本库一模一样的状态;

    一种是readme.md已经添加到暂存区后,又作了修改,现在,撤销修改就回到添加到暂存区后的状态。

    总之,就是让这个文件回到最近一次git commitgit add时的状态。

    git checkout -- file命令中的--很重要,没有--,就变成了“切换到另一个分支”的命令,我们在后面的分支管理中会再次遇到git checkout命令。

     

    现在假定是凌晨3点,你不但写了一些胡话,还git add到暂存区了:

    1 $ cat readme.md
    2 Git is a distributed version control system.
    3 Git is free software distributed under the GPL.
    4 Git has a mutable index called stage.
    5 Git tracks changes of files.
    6 My stupid boss still prefers SVN.
    7  
    8 $ git add readme.md

    庆幸的是,在commit之前,你发现了这个问题。用git status查看一下,修改只是添加到了暂存区,还没有提交:

    1 $ git status
    2 On branch master
    3 Changes to be committed:
    4   (use "git reset HEAD <file>..." to unstage)
    5  
    6     modified:   readme.md
    7 </file>

    Git同样告诉我们,用命令git reset HEAD file可以把暂存区的修改撤销掉(unstage),重新放回工作区:

    1 $ git reset HEAD readme.md
    2 Unstaged changes after reset:
    3 M   readme.md

    git reset命令既可以回退版本,也可以把暂存区的修改回退到工作区。当我们用HEAD时,表示最新的版本。

    再用git status查看一下,现在暂存区是干净的,工作区有修改

    1 $ git status
    2 # On branch master
    3 # Changes not staged for commit:
    4 #   (use "git add <file>..." to update what will be committed)
    5 #   (use "git checkout -- <file>..." to discard changes in working directory)
    6 #
    7 #       modified:   readme.md
    8 #
    9 no changes added to commit (use "git add" and/or "git commit -a")

    还记得如何丢弃工作区的修改吗?

    1 $ git checkout -- readme.md
    2  
    3 $ more readme.md
    4 #git study repo

     

    删除操作

    在Git中,删除也是一个修改操作,我们实战一下,先添加一个新文件test.txt到Git并且提交:

    1 $ git add .
    2 $ git commit -m "add test.txt"
    3 [master a8fa95a] add test.txt
    4  1 file changed, 0 insertions(+), 0 deletions(-)
    5  create mode 100644 test.txt

    一般情况下,你通常直接在文件管理器中把没用的文件删了,或者用rm命令删了

    1 rm test.txt

    这个时候,Git知道你删除了文件,因此,工作区和版本库就不一致了,git status命令会立刻告诉你哪些文件被删除了:

    1 $ git status
    2 On branch master
    3 Changes not staged for commit:
    4   (use "git add/rm <file>..." to update what will be committed)
    5   (use "git checkout -- <file>..." to discard changes in working directory)
    6  
    7     deleted:    test.txt
    8  
    9 no changes added to commit (use "git add" and/or "git commit -a")

    现在你有两个选择,一是确实要从版本库中删除该文件,那就用命令git rm删掉,并且git commit

    1 $ git rm test.txt
    2 rm 'test.txt'
    3  
    4 $ git commit -m "remove test"
    5 [master 03df00a] remove test
    6  1 file changed, 0 insertions(+), 0 deletions(-)
    7  delete mode 100644 test.txt

    现在,文件就从版本库中被删除了。

    另一种情况是删错了,因为版本库里还有呢,所以可以很轻松地把误删的文件恢复到最新版本:

    1 $ git checkout -- test.txt

    git checkout其实是用版本库里的版本替换工作区的版本,无论工作区是修改还是删除,都可以“一键还原”。

     

    远程仓库

    到目前为止,我们已经掌握了如何在Git仓库里对一个文件进行时光穿梭,你再也不用担心文件备份或者丢失的问题了。

    可是有用过集中式版本控制系统SVN的童鞋会站出来说,这些功能在SVN里早就有了,没看出Git有什么特别的地方。

    没错,如果只是在一个仓库里管理文件历史,Git和SVN真没啥区别。为了保证你现在所学的Git物超所值,将来绝对不会后悔,同时为了打击已经不幸学了SVN的童鞋,本章开始介绍Git的杀手级功能之一(注意是之一,也就是后面还有之二,之三……):远程仓库。

    Git是分布式版本控制系统,同一个Git仓库,可以分布到不同的机器上。怎么分布呢?最早,肯定只有一台机器有一个原始版本库,此后,别的机器可以“克隆”这个原始版本库,而且每台机器的版本库其实都是一样的,并没有主次之分。

    你肯定会想,至少需要两台机器才能玩远程库不是?但是我只有一台电脑,怎么玩?

    其实一台电脑上也是可以克隆多个版本库的,只要不在同一个目录下。不过,现实生活中是不会有人这么傻的在一台电脑上搞几个远程库玩,因为一台电脑上搞几个远程库完全没有意义,而且硬盘挂了会导致所有库都挂掉,所以我也不告诉你在一台电脑上怎么克隆多个仓库。

    实际情况往往是这样,找一台电脑充当服务器的角色,每天24小时开机,其他每个人都从这个“服务器”仓库克隆一份到自己的电脑上,并且各自把各自的提交推送到服务器仓库里,也从服务器仓库中拉取别人的提交。

    完全可以自己搭建一台运行Git的服务器,不过现阶段,为了学Git先搭个服务器绝对是小题大作。好在这个世界上有个叫GitHub的神奇的网站,从名字就可以看出,这个网站就是提供Git仓库托管服务的,所以,只要注册一个GitHub账号,就可以免费获得Git远程仓库。

    在继续阅读后续内容前,请自行注册GitHub账号。由于你的本地Git仓库和GitHub仓库之间的传输是通过SSH加密的,所以,需要一点设置:

    第1步:创建SSH Key。在用户主目录下,看看有没有.ssh目录,如果有,再看看这个目录下有没有id_rsaid_rsa.pub这两个文件,如果已经有了,可直接跳到下一步。如果没有,打开Shell(Windows下打开Git Bash),创建SSH Key:

    1 $ ssh-keygen -t rsa -C "youremail@example.com"

    你需要把邮件地址换成你自己的邮件地址,然后一路回车,使用默认值即可,由于这个Key也不是用于军事目的,所以也无需设置密码。

    如果一切顺利的话,可以在用户主目录里找到.ssh目录,里面有id_rsaid_rsa.pub两个文件,这两个就是SSH Key的秘钥对,id_rsa是私钥,不能泄露出去,id_rsa.pub是公钥,可以放心地告诉任何人。

    第2步:登陆GitHub,打开“Account settings”,“SSH Keys”页面:

    然后,点“Add SSH Key”,填上任意Title,在Key文本框里粘贴id_rsa.pub文件的内容:

    点“Add Key”,你就应该看到已经添加的Key

    为什么GitHub需要SSH Key呢?因为GitHub需要识别出你推送的提交确实是你推送的,而不是别人冒充的,而Git支持SSH协议,所以,GitHub只要知道了你的公钥,就可以确认只有你自己才能推送。

    当然,GitHub允许你添加多个Key。假定你有若干电脑,你一会儿在公司提交,一会儿在家里提交,只要把每台电脑的Key都添加到GitHub,就可以在每台电脑上往GitHub推送了。

    最后友情提示,在GitHub上免费托管的Git仓库,任何人都可以看到喔(但只有你自己才能改)。所以,不要把敏感信息放进去。

    如果你不想让别人看到Git库,有两个办法,一个是交点保护费,让GitHub把公开的仓库变成私有的,这样别人就看不见了(不可读更不可写)。另一个办法是自己动手,搭一个Git服务器,因为是你自己的Git服务器,所以别人也是看不见的。这个方法我们后面会讲到的,相当简单,公司内部开发必备。

    确保你拥有一个GitHub账号后,我们就即将开始远程仓库的学习。

     

    远程创建仓库

    现在的情景是,你已经在本地创建了一个Git仓库后,又想在GitHub创建一个Git仓库,并且让这两个仓库进行远程同步,这样,GitHub上的仓库既可以作为备份,又可以让其他人通过该仓库来协作,真是一举多得。

    首先,登陆GitHub,然后,在右上角找到“New repository”按钮,创建一个新的仓库:

     

     

    创建好的仓库

    目前,在GitHub上的这个oldboy_website仓库还是空的,GitHub告诉我们,可以从这个仓库克隆出新的仓库,也可以把一个已有的本地仓库与之关联,然后,把本地仓库的内容推送到GitHub仓库。

    现在,我们根据GitHub的提示,在本地已有的git_trainning仓库下运行命令:

     1 $ git remote add origin git@github.com:triaquae/oldboy_website.git #添加远程仓库
     2 $ git push -u origin master #推到远程
     3  
     4 The authenticity of host 'github.com (192.30.253.113)' can't be established.
     5 RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.
     6 Are you sure you want to continue connecting (yes/no)? yes   #第一次推会出现,写yes
     7 Warning: Permanently added 'github.com,192.30.253.113' (RSA) to the list of known hosts.
     8 Counting objects: 20, done.
     9 Delta compression using up to 8 threads.
    10 Compressing objects: 100% (14/14), done.
    11 Writing objects: 100% (20/20), 1.76 KiB | 0 bytes/s, done.
    12 Total 20 (delta 4), reused 0 (delta 0)
    13 remote: Resolving deltas: 100% (4/4), done.
    14 To git@github.com:triaquae/oldboy_website.git
    15  * [new branch]      master -> master
    16 Branch master set up to track remote branch master from origin.

    请千万注意,把上面的triaquae替换成你自己的GitHub账户名,否则,你在本地关联的就是我的远程库,关联没有问题,但是你以后推送是推不上去的,因为你的SSH Key公钥不在我的账户列表中。

    添加后,远程库的名字就是origin,这是Git默认的叫法,也可以改成别的,但是origin这个名字一看就知道是远程库。

    把本地库的内容推送到远程,用git push命令,实际上是把当前分支master推送到远程。  

     

    此时刷新远程仓库页面, 就看到了你刚从本地推上来的代码了

    从现在起,只要本地作了提交,就可以通过命令:

    1 $ git push origin master

    what ? 不信?那帮你试一下吧

    创建一个index.html文件,同时上传到远程

     1 $ vim index.html
     2 $ git add .
     3 $ git commit -m "add home page"
     4  
     5 [master 8675486] add home page
     6  1 file changed, 6 insertions(+)
     7  create mode 100644 index.html
     8  
     9 $ git push origin master #推到远程
    10  
    11 Counting objects: 3, done.
    12 Delta compression using up to 8 threads.
    13 Compressing objects: 100% (3/3), done.
    14 Writing objects: 100% (3/3), 362 bytes | 0 bytes/s, done.
    15 Total 3 (delta 0), reused 0 (delta 0)
    16 To git@github.com:triaquae/oldboy_website.git
    17    03df00a..8675486  master -> master

    然后刷新下远程仓库页面,就看到你的新创建的文件了

     

    从远程库克隆

    我们讲了先有本地库,后有远程库的时候,如何关联远程库。

    现在,假设我们从零开发,那么最好的方式是先创建远程库,然后,从远程库克隆。

    首先,登陆GitHub,创建一个新的仓库,名字叫gitskills

    我们勾选Initialize this repository with a README,这样GitHub会自动为我们创建一个README.md文件。创建完毕后,可以看到README.md文件:

    现在,远程库已经准备好了,下一步是用命令git clone克隆一个本地库:

    在本地找一个你想存放这个远程仓库的目录,然后在本地命令行用git clone 命令来克隆这个远程库

     1 $ git clone git@github.com:triaquae/gitskills.git
     2 Cloning into 'gitskills'...
     3 Warning: Permanently added the RSA host key for IP address '192.30.253.112' to the list of known hosts.
     4 remote: Counting objects: 3, done.
     5 remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
     6 Receiving objects: 100% (3/3), done.
     7 Checking connectivity... done.
     8  
     9 $ cd gitskills/  #进入刚clone下来的目录
    10 $ ls
    11 README.md

    如果有多个人协作开发,那么每个人各自从远程克隆一份就可以了。

    你也许还注意到,GitHub给出的地址不止一个,还可以用https://github.com/triaquae/gitskills.git 这样的地址。实际上,Git支持多种协议,默认的git://使用ssh,但也可以使用https等其他协议。

    使用https除了速度慢以外,还有个最大的麻烦是每次推送都必须输入口令,但是在某些只开放http端口的公司内部就无法使用ssh协议而只能用https

     

    分支管理

    分支在实际中有什么用呢?假设你准备开发一个新功能,但是需要两周才能完成,第一周你写了50%的代码,如果立刻提交,由于代码还没写完,不完整的代码库会导致别人不能干活了。如果等代码全部写完再一次提交,又存在丢失每天进度的巨大风险。

    现在有了分支,就不用怕了。你创建了一个属于你自己的分支,别人看不到,还继续在原来的分支上正常工作,而你在自己的分支上干活,想提交就提交,直到开发完毕后,再一次性合并到原来的分支上,这样,既安全,又不影响别人工作。

    其他版本控制系统如SVN等都有分支管理,但是用过之后你会发现,这些版本控制系统创建和切换分支比蜗牛还慢,简直让人无法忍受,结果分支功能成了摆设,大家都不去用。

    但Git的分支是与众不同的,无论创建、切换和删除分支,Git在1秒钟之内就能完成!无论你的版本库是1个文件还是1万个文件。

     

    创建与合并分支 

    在学习版本回退部分时,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。HEAD严格来说不是指向提交,而是指向mastermaster才是指向提交的,所以,HEAD指向的就是当前分支。

    一开始的时候,master分支是一条线,Git用master指向最新的提交,再用HEAD指向master,就能确定当前分支,以及当前分支的提交点:

    每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长, 当我们创建新的分支,例如dev时,Git新建了一个指针叫dev,指向master相同的提交,再把HEAD指向dev,就表示当前分支在dev上:

    假如我们在dev上的工作完成了,就可以把dev合并到master上。Git怎么合并呢?最简单的方法,就是直接把master指向dev的当前提交,就完成了合并:

    所以Git合并分支也很快!就改改指针,工作区内容也不变!

    合并完分支后,甚至可以删除dev分支。删除dev分支就是把dev指针给删掉,删掉后,我们就剩下了一条master分支:

     

     

    下面开始实战

    首先,我们创建dev分支,然后切换到dev分支:

    1 $ git checkout -b dev
    2 Switched to a new branch 'dev'

    git checkout命令加上-b参数表示创建并切换,相当于以下两条命令:

    1 $ git branch dev
    2 $ git checkout dev
    3 Switched to branch 'dev'

    然后,用git branch命令查看当前分支:

    1 $ git branch
    2 * dev
    3   master

    git branch命令会列出所有分支,当前分支前面会标一个*号。

    然后,我们就可以在dev分支上正常提交,比如对readme.txt做个修改,加上一行:

    1 Creating a new branch is quick.

    然后提交:

    1 $ git add readme.txt
    2 $ git commit -m "branch test"
    3 [dev fec145a] branch test
    4  1 file changed, 1 insertion(+)

    现在,dev分支的工作完成,我们就可以切换回master分支:

    1 $ git checkout master
    2 Switched to branch 'master'

    切换回master分支后,再查看一个readme.txt文件,刚才添加的内容不见了!因为那个提交是在dev分支上,而master分支此刻的提交点并没有变:

    现在,我们把dev分支的工作成果合并到master分支上:

    1 $ git merge dev
    2 Updating d17efd8..fec145a
    3 Fast-forward
    4  readme.txt |    1 +
    5  1 file changed, 1 insertion(+)

    git merge命令用于合并指定分支到当前分支。合并后,再查看readme.txt的内容,就可以看到,和dev分支的最新提交是完全一样的。

    注意到上面的Fast-forward信息,Git告诉我们,这次合并是“快进模式”,也就是直接把master指向dev的当前提交,所以合并速度非常快。

    当然,也不是每次合并都能Fast-forward,我们后面会讲其他方式的合并。

    合并完成后,就可以放心地删除dev分支了:

    1 $ git branch -d dev
    2 Deleted branch dev (was fec145a).

    删除后,查看branch,就只剩下master分支了:

     $ git branch * master 

    因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。

     

    解决冲突

    人生不如意之事十之八九,合并分支往往也不是一帆风顺的。

    准备新的feature1分支,继续我们的新分支开发:

    1 $ git checkout -b feature1
    2 Switched to a new branch 'feature1'

    修改readme.txt最后一行,改为:

    1 added this line from branch feature 1

    feature1分支上提交:

    $ git add readme.txt 
    $ git commit -m "add feature"
    [feature1 75a857c] AND simple
     1 file changed, 1 insertion(+), 1 deletion(-)
    

    切换到master分支:

    $ git checkout master
    Switched to branch 'master'
    Your branch is ahead of 'origin/master' by 1 commit.
    

    Git还会自动提示我们当前master分支比远程的master分支要超前1个提交。

    master分支上把readme.txt文件的最后一行改为:

    1 added this line from master

    提交:

    $ git add readme.txt 
    $ git commit -m "master update"
    [master 400b400] & simple
     1 file changed, 1 insertion(+), 1 deletion(-)
    

    现在,master分支和feature1分支各自都分别有新的提交,变成了这样:

    这种情况下,Git无法执行“快速合并”,只能试图把各自的修改合并起来,但这种合并就可能会有冲突,我们试试看:

     1 $ git status
     2 # On branch master
     3 # Your branch is ahead of 'origin/master' by 2 commits.
     4 #
     5 # Unmerged paths:
     6 #   (use "git add/rm <file>..." as appropriate to mark resolution)
     7 #
     8 #       both modified:      readme.txt
     9 #
    10 no changes added to commit (use "git add" and/or "git commit -a")

    我们可以直接查看readme.txt的内容:

    1 #git study repo
    2 Creating a new branch is quick.
    3 <<<<<<< HEAD
    4 added this line from master
    5 =======
    6 added this line from branch feature 1
    7 >>>>>>> feature1

    Git用<<<<<<<=======>>>>>>>标记出不同分支的内容,我们修改如下后保存:

    1 #git study repo
    2 Creating a new branch is quick.
    3 added this line from master
    4 added this line from branch feature 1

    现在,master分支和feature1分支变成了下图所示:

    用带参数的git log也可以看到分支的合并情况:

    1 $ git log --graph --pretty=oneline
    2 *   feedd786cad3e18323a41846fcc1b0d52fc0c98e fix conflict
    3 |\ 
    4 | * 01f8f8d168e113fac9fbe24c4cfa6d4c351a9821 update from branch
    5 * | 743ccee30f3d74f1993f17e7312032b7399b1306 from master
    6 |/ 
    7 * edfbc29982927236596539e0f1971b0575f803c0 branch test
    8 * 8675486bfeeb340914369e80d2cfcf3e854e88a3 add home page

    分支策略

    在实际开发中,我们应该按照几个基本原则进行分支管理:

    首先,master分支应该是非常稳定的,也就是仅用来发布新版本,平时不能在上面干活;

    那在哪干活呢?干活都在dev分支上,也就是说,dev分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev分支合并到master上,在master分支发布1.0版本;

    你和你的小伙伴们每个人都在dev分支上干活,每个人都有自己的分支,时不时地往dev分支上合并就可以了。

    所以,团队合作的分支看起来就像这样:

     

     

    bug分支  

    软件开发中,bug就像家常便饭一样。有了bug就需要修复,在Git中,由于分支是如此的强大,所以,每个bug都可以通过一个新的临时分支来修复,修复后,合并分支,然后将临时分支删除。

    当你接到一个修复一个代号101的bug的任务时,很自然地,你想创建一个分支issue-101来修复它,但是,等等,当前正在dev上进行的工作还没有提交:

     1 $ git status
     2 # On branch dev
     3 # Changes to be committed:
     4 #   (use "git reset HEAD <file>..." to unstage)
     5 #
     6 #       new file:   hello.py
     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:   readme.txt

    并不是你不想提交,而是工作只进行到一半,还没法提交,预计完成还需1天时间。但是,必须在两个小时内修复该bug,怎么办?

    幸好,Git还提供了一个stash功能,可以把当前工作现场“储藏”起来,等以后恢复现场后继续工作:

    1 $ git stash
    2 Saved working directory and index state WIP on dev: 6224937 add merge
    3 HEAD is now at 6224937 add merge

    现在,用git status查看工作区,就是干净的(除非有没有被Git管理的文件),因此可以放心地创建分支来修复bug。

    首先确定要在哪个分支上修复bug,假定需要在master分支上修复,就从master创建临时分支:

    1 $ git checkout master
    2 Switched to branch 'master'
    3 Your branch is ahead of 'origin/master' by 6 commits.
    4 $ git checkout -b issue-101
    5 Switched to a new branch 'issue-101'

    现在修复bug,需要把“Git is free software ...”改为“Git is a free software ...”,然后提交:

    1 $ git add readme.txt
    2 $ git commit -m "fix bug 101"
    3 [issue-101 cc17032] fix bug 101
    4  1 file changed, 1 insertion(+), 1 deletion(-)

    修复完成后,切换到master分支,并完成合并,最后删除issue-101分支:

    1 $ git checkout master
    2 Switched to branch 'master'
    3 Your branch is ahead of 'origin/master' by 2 commits.
    4 $ git merge --no-ff -m "merged bug fix 101" issue-101
    5 Merge made by the 'recursive' strategy.
    6  readme.txt |    2 +-
    7  1 file changed, 1 insertion(+), 1 deletion(-)
    8 $ git branch -d issue-101
    9 Deleted branch issue-101 (was cc17032).

    太棒了,原计划两个小时的bug修复只花了5分钟!现在,是时候接着回到dev分支干活了!

    1 $ git checkout dev
    2 Switched to branch 'dev'
    3 $ git status
    4 # On branch dev
    5 nothing to commit (working directory clean)

    工作区是干净的,刚才的工作现场存到哪去了?用git stash list命令看看:

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

    工作现场还在,Git把stash内容存在某个地方了,但是需要恢复一下,有两个办法:

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

    另一种方式是用git stash pop,恢复的同时把stash内容也删了:

     1 $ git stash pop
     2 # On branch dev
     3 # Changes to be committed:
     4 #   (use "git reset HEAD <file>..." to unstage)
     5 #
     6 #       new file:   hello.py
     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:   readme.txt
    13 #
    14 Dropped refs/stash@{0} (f624f8e5f082f2df2bed8a4e09c12fd2943bdd40)

    再用git stash list查看,就看不到任何stash内容了:

    1 $ git stash list

    你可以多次stash,恢复的时候,先用git stash list查看,然后恢复指定的stash,用命令:

    1 $ git stash apply stash@{0}

     

    多人协作  

    当你从远程仓库克隆时,实际上Git自动把本地的master分支和远程的master分支对应起来了,并且,远程仓库的默认名称是origin

    要查看远程库的信息,用git remote

    1 $ git remote
    2 origin

    或者,用git remote -v显示更详细的信息:

    1 $ git remote -v
    2 origin  git@github.com:triaquae/gitskills.git (fetch)
    3 origin  git@github.com:triaquae/gitskills.git (push)

    上面显示了可以抓取和推送的origin的地址。如果没有推送权限,就看不到push的地址。

    推送分支

    推送分支,就是把该分支上的所有本地提交推送到远程库。推送时,要指定本地分支,这样,Git就会把该分支推送到远程库对应的远程分支上:

    1 $ git push origin master

    如果要推送其他分支,比如dev,就改成:

    1 $ git push origin dev

    但是,并不是一定要把本地分支往远程推送,那么,哪些分支需要推送,哪些不需要呢?

    • master分支是主分支,因此要时刻与远程同步;

    • dev分支是开发分支,团队所有成员都需要在上面工作,所以也需要与远程同步;

    • bug分支只用于在本地修复bug,就没必要推到远程了,除非老板要看看你每周到底修复了几个bug;

    • feature分支是否推到远程,取决于你是否和你的小伙伴合作在上面开发。

    总之,就是在Git中,分支完全可以在本地自己藏着玩,是否推送,视你的心情而定!

    10.2 抓取分支

    多人协作时,大家都会往masterdev分支上推送各自的修改。

    现在,模拟一个你的小伙伴,可以在另一台电脑(注意要把SSH Key添加到GitHub)或者同一台电脑的另一个目录下克隆:

    1 $ git clone git@github.com:triaquae/gitskills.git
    2 Cloning into 'gitskills'...
    3 remote: Counting objects: 16, done.
    4 remote: Compressing objects: 100% (7/7), done.
    5 remote: Total 16 (delta 0), reused 10 (delta 0), pack-reused 0
    6 Receiving objects: 100% (16/16), done.
    7 Checking connectivity... done

    当你的小伙伴从远程库clone时,默认情况下,你的小伙伴只能看到本地的master分支。不信可以用git branch命令看看:

    1 $ git branch
    2 * master

    现在,你的小伙伴要在dev分支上开发,就必须创建远程origindev分支到本地,于是他用这个命令创建本地dev分支:

    1 $ git checkout -b dev origin/dev

    现在,他就可以在dev上继续修改,然后,时不时地把dev分支push到远程:

     1 $ git add .
     2 $ git commit -m "small updates"
     3  
     4 [dev f1b762e] small updates
     5  2 files changed, 5 insertions(+), 1 deletion(-)
     6 Alexs-MacBook-Pro:gitskills alex$ git push origin dev
     7 Counting objects: 4, done.
     8 Delta compression using up to 8 threads.
     9 Compressing objects: 100% (3/3), done.
    10 Writing objects: 100% (4/4), 438 bytes | 0 bytes/s, done.
    11 Total 4 (delta 0), reused 0 (delta 0)
    12 To git@github.com:triaquae/gitskills.git
    13    33ec6b4..f1b762e  dev -> dev

    你的小伙伴已经向origin/dev分支推送了他的提交,而碰巧你也对同样的文件作了修改,并试图推送:

     1 $ git add .
     2 $ git commit -m "add Dog class"
     3 [dev 7e7b1bf] add Dog class
     4  2 files changed, 7 insertions(+)
     5  
     6  
     7 $ git push origin dev
     8  
     9 To git@github.com:triaquae/gitskills.git
    10  ! [rejected]        dev -> dev (fetch first)
    11 error: failed to push some refs to 'git@github.com:triaquae/gitskills.git'
    12 hint: Updates were rejected because the remote contains work that you do
    13 hint: not have locally. This is usually caused by another repository pushing
    14 hint: to the same ref. You may want to first integrate the remote changes
    15 hint: (e.g., 'git pull ...') before pushing again. #提示你了,先把远程最新的拉下来再提交你的
    16 hint: See the 'Note about fast-forwards' in 'git push --help' for details.

    推送失败,因为你的小伙伴的最新提交和你试图推送的提交有冲突,解决办法也很简单,Git已经提示我们,先用git pull把最新的提交从origin/dev抓下来,然后,在本地合并,解决冲突,再推

     1 $ git pull
     2 remote: Counting objects: 4, done.
     3 remote: Compressing objects: 100% (3/3), done.
     4 remote: Total 4 (delta 0), reused 4 (delta 0), pack-reused 0
     5 Unpacking objects: 100% (4/4), done.
     6 From github.com:triaquae/gitskills
     7    33ec6b4..f1b762e  dev        -> origin/dev
     8 There is no tracking information for the current branch.
     9 Please specify which branch you want to merge with.
    10 See git-pull(1) for details.
    11  
    12     git pull <remote> <branch>
    13  
    14 If you wish to set tracking information for this branch you can do so with:
    15  
    16     git branch --set-upstream-to=origin/<branch> dev

    git pull也失败了,原因是没有指定本地dev分支与远程origin/dev分支的链接,根据提示,设置devorigin/dev的链接:

    1 $ git branch --set-upstream-to=origin/dev dev
    2 Branch dev set up to track remote branch dev from origin.

    再pull:

    1 $ git pull
    2 Auto-merging hello.py
    3 CONFLICT (content): Merge conflict in hello.py
    4 Auto-merging branch_test.md
    5 CONFLICT (content): Merge conflict in branch_test.md
    6 Automatic merge failed; fix conflicts and then commit the result.

    这回git pull成功,但是合并有冲突,需要手动解决,解决的方法和分支管理中的解决冲突完全一样。解决后,提交,再push:

     1 $ git add .
     2 $ git commit -m "merge & fix hello.py"
     3 [dev 93e28e3] merge & fix hello.py
     4  
     5 $ git push origin dev
     6  
     7 Counting objects: 8, done.
     8 Delta compression using up to 8 threads.
     9 Compressing objects: 100% (7/7), done.
    10 Writing objects: 100% (8/8), 819 bytes | 0 bytes/s, done.
    11 Total 8 (delta 1), reused 0 (delta 0)
    12 remote: Resolving deltas: 100% (1/1), done.
    13 To git@github.com:triaquae/gitskills.git
    14    f1b762e..93e28e3  dev -> dev

    因此,多人协作的工作模式通常是这样:

    1. 首先,可以试图用git push origin branch-name推送自己的修改;

    2. 如果推送失败,则因为远程分支比你的本地更新,需要先用git pull试图合并;

    3. 如果合并有冲突,则解决冲突,并在本地提交;

    4. 没有冲突或者解决掉冲突后,再用git push origin branch-name推送就能成功!

    如果git pull提示“no tracking information”,则说明本地分支和远程分支的链接关系没有创建,用命令git branch --set-upstream branch-name origin/branch-name

    这就是多人协作的工作模式,一旦熟悉了,就非常简单。

     

    github使用

    我们一直用GitHub作为免费的远程仓库,如果是个人的开源项目,放到GitHub上是完全没有问题的。其实GitHub还是一个开源协作社区,通过GitHub,既可以让别人参与你的开源项目,也可以参与别人的开源项目。

    在GitHub出现以前,开源项目开源容易,但让广大人民群众参与进来比较困难,因为要参与,就要提交代码,而给每个想提交代码的群众都开一个账号那是不现实的,因此,群众也仅限于报个bug,即使能改掉bug,也只能把diff文件用邮件发过去,很不方便。

    但是在GitHub上,利用Git极其强大的克隆和分支功能,广大人民群众真正可以第一次自由参与各种开源项目了。

    如何参与一个开源项目呢?比如人气极高的bootstrap项目,这是一个非常强大的CSS框架,你可以访问它的项目主页https://github.com/twbs/bootstrap,点“Fork”就在自己的账号下克隆了一个bootstrap仓库,然后,从自己的账号下clone:

    1 git clone git@github.com:michaelliao/bootstrap.git

    一定要从自己的账号下clone仓库,这样你才能推送修改。如果从bootstrap的作者的仓库地址git@github.com:twbs/bootstrap.git克隆,因为没有权限,你将不能推送修改。

    Bootstrap的官方仓库twbs/bootstrap、你在GitHub上克隆的仓库my/bootstrap,以及你自己克隆到本地电脑的仓库,他们的关系就像下图显示的那样:

     

    如果你想修复bootstrap的一个bug,或者新增一个功能,立刻就可以开始干活,干完后,往自己的仓库推送。

    如果你希望bootstrap的官方库能接受你的修改,你就可以在GitHub上发起一个pull request。当然,对方是否接受你的pull request就不一定了。

    小结

    • 在GitHub上,可以任意Fork开源仓库;

    • 自己拥有Fork后的仓库的读写权限;

    • 可以推送pull request给官方仓库来贡献代码。

     

    忽略特殊文件.gitignore

    有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件啦,等等,每次git status都会显示Untracked files ...,有强迫症的童鞋心里肯定不爽。

    好在Git考虑到了大家的感受,这个问题解决起来也很简单,在Git工作区的根目录下创建一个特殊的.gitignore文件,然后把要忽略的文件名填进去,Git就会自动忽略这些文件。

    不需要从头写.gitignore文件,GitHub已经为我们准备了各种配置文件,只需要组合一下就可以使用了。所有配置文件可以直接在线浏览:https://github.com/github/gitignore

    忽略文件的原则是:

    1. 忽略操作系统自动生成的文件,比如缩略图等;
    2. 忽略编译生成的中间文件、可执行文件等,也就是如果一个文件是通过另一个文件自动生成的,那自动生成的文件就没必要放进版本库,比如Java编译产生的.class文件;
    3. 忽略你自己的带有敏感信息的配置文件,比如存放口令的配置文件。

    举个例子:

    假设你在Windows下进行Python开发,Windows会自动在有图片的目录下生成隐藏的缩略图文件,如果有自定义目录,目录下就会有Desktop.ini文件,因此你需要忽略Windows自动生成的垃圾文件:

    1 # Windows:
    2 Thumbs.db
    3 ehthumbs.db
    4 Desktop.ini

    然后,继续忽略Python编译产生的.pyc.pyodist等文件或目录:

    1 # Python:
    2 *.py[cod]
    3 *.so
    4 *.egg
    5 *.egg-info
    6 dist
    7 build

    加上你自己定义的文件,最终得到一个完整的.gitignore文件,内容如下:

     1 # Windows:
     2 Thumbs.db
     3 ehthumbs.db
     4 Desktop.ini
     5  
     6 # Python:
     7 *.py[cod]
     8 *.so
     9 *.egg
    10 *.egg-info
    11 dist
    12 build
    13  
    14 # My configurations:
    15 db.ini
    16 deploy_key_rsa

    最后一步就是把.gitignore也提交到Git,就完成了!当然检验.gitignore的标准是git status命令是不是说working directory clean

    使用Windows的童鞋注意了,如果你在资源管理器里新建一个.gitignore文件,它会非常弱智地提示你必须输入文件名,但是在文本编辑器里“保存”或者“另存为”就可以把文件保存为.gitignore了。

    有些时候,你想添加一个文件到Git,但发现添加不了,原因是这个文件被.gitignore忽略了:

    1 $ git add App.class
    2 The following paths are ignored by one of your .gitignore files:
    3 App.class
    4 Use -f if you really want to add them.

    如果你确实想添加该文件,可以用-f强制添加到Git:

    1 $ git add -f App.class

    或者你发现,可能是.gitignore写得有问题,需要找出来到底哪个规则写错了,可以用git check-ignore命令检查:

    1 $ git check-ignore -v App.class
    2 .gitignore:3:*.class    App.class

    Git会告诉我们,.gitignore的第3行规则忽略了该文件,于是我们就可以知道应该修订哪个规则。

    小结

    • 忽略某些文件时,需要编写.gitignore

    • .gitignore文件本身要放到版本库里,并且可以对.gitignore做版本管理!

     

    以上文章大量参考或转载

    http://www.cnblogs.com/alex3714/articles/5930846.html

    转载于:https://www.cnblogs.com/YingLai/p/6825911.html

    展开全文
  • Git & Github

    2019-07-07 18:46:12
    为什么要用版本控制? 假设你在的公司要上线一个新功能,你们开发团队为实现这个新功能,写了大约5000行代码,上线没2天,就发现...所以你急需要一个工具,能帮你记录每次对代码做了哪些修改,并且可以轻易的把代码...
  • git &github 快速入门

    2019-06-24 11:11:44
    为什么要用版本控制? 假设你在的公司要上线一个新功能,你们开发团队为实现这个新功能,写了大约5000行代码,上线没2天,...所以你急需要一个工具,能帮你记录每次对代码做了哪些修改,并且可以轻易的把代码回滚到...
  • GIt以其方便安全快捷的特点,在版本控制领域可谓是大放光彩,深受广大开发者的喜爱。优点就不多说了,后面省去一大堆字……GIt常用的知识点不多,但是所有其他细节内容也绝对不少,本文旨在介绍/记录常用的知识点,...
  • SVN使用教程

    2019-03-04 16:39:42
    git的使用[转] 本节内容 github介绍 安装 仓库创建&amp;...提交代码 ...代码回滚 ...假设你在的公司要上线一个新功能,你们开发团队为实现这个新功能,写了大约5000行代码,...
  • github使用

    2018-09-04 14:06:47
    提交代码 代码回滚 工作区和暂存区 撤销修改 删除操作 远程仓库 分支管理 多人协作 github使用 忽略特殊文件.gitignore &nbsp; &nbsp; 为什么要用版本控制? 假设你在的公司要上线一个新功能,你们开发团队...
  • 你是否有过这样的经历:明明感觉电脑里什么都没装,macOS 却弹出了储存空间不足的警告。就算你忍痛删掉了一些个人文件,也只释放出了几百 MB 空间,警示框...缓存垃圾速速退散 冗余文件构成 从你第一次按下 Mac 开...
  • Git And GitHub

    2017-05-21 07:17:41
    github介绍安装仓库创建& 提交代码代码回滚工作区和暂存区撤销修改删除操作远程仓库分支管理多人协作github使用忽略特殊文件.gitignore     为什么要用版本控制? 假设你在的公司要上线一个新功能,...
  • git的使用[转]

    2019-01-13 22:23:50
    本节内容 github介绍 安装 仓库创建&amp;...假设你在的公司要上线一个新功能,你们开发团队为实现这个新功能,写了大约5000行代码,上线没2天,就发现这个功能用户并不喜欢,你老板让你去...
  • Git & github 入门(上)

    2019-08-14 14:16:16
    本节内容 github介绍 安装 仓库创建&...假设你在的公司要上线一个新功能,你们开发团队为实现这个新功能,写了大约5000行代码,上线没2天,就发现这个功能用户并不喜欢,你老板让你去掉这...
  • g4e 是 Git for Enterprise Developer的简写,这个系列文章会统一使用g4e作为标识,便于大家查看和搜索。 章节目录 ...起步 1 – 创建分支和保存代码 起步 2 – 了解Git历史记录 起步 3 – 拉...
  • git & github 快速入门

    2019-08-09 18:51:20
    本节内容 github介绍 安装 仓库创建&提交代码 ...代码回滚 ...假设你在的公司要上线一个新功能,你们开发团队为实现这个新功能,写了大约5000行代码,上线没2天,就发现这个功能用户并不喜欢...
1 2 3
收藏数 46
精华内容 18