图解git基本使用

图解Git

此页图解git中的最经常使用命令。若是你稍微理解git的工做原理,这篇文章可以让你理解的更透彻。 若是你想知道这个站点怎样产生,请前往GitHub repositoryphp

git配置文件html

[user]
	name = zhaoyingchao
	email = zyc@alibaba-inc.com

[alias]
	st = status -sb
	co = checkout
	br = branch -a
	mg = merge
	ci = commit
	cil = commit --amend
	ds = diff --staged
	dt = difftool
	mt = mergetool
	last = log -1 HEAD
	latest = for-each-ref --sort=-committerdate --format=\"%(committername)@%(refname:short) [%(committerdate:short)] %(contents)\"
	ls = log --pretty=format:\"%C(yellow)%h %C(blue)%ad %C(red)%d %C(reset)%s %C(green)[%cn]\" --decorate --date=short
	hist = log --pretty=format:\"%C(yellow)%h %C(red)%d %C(reset)%s %C(green)[%an] %C(blue)%ad\" --topo-order --graph --date=short
	type = cat-file -t
	dump = cat-file -p
	lg = log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
	lgc = log --branches --not --remotes
	lgac =log --branches --not --remotes --simplify-by-decoration --decorate --online
[core]
	autocrlf = true
	
[push]
	default = simple

[credential]
	helper = store
	username = zhaoyingchao

正文

 

这里写图片描述

  1. 基本用法
  2. 约定
  3. 命令详解
    1. Diff
    2. Commit
    3. Checkout
    4. Detached HEAD(匿名分支提交)
    5. Reset
    6. Merge
    7. Cherry Pick
    8. Rebase
  4. 技术说明

基本用法

上面的四条命令在工做目录、暂存目录(也叫作索引)和仓库之间复制文件。git

  • git add files 把当前文件放入暂存区域。
  • git commit 给暂存区域生成快照并提交。
  • git reset -- files 用来撤销最后一次git add files,你也能够用git reset 撤销全部暂存区域文件。
  • git checkout -- files 把文件从暂存区域复制到工做目录,用来丢弃本地修改。

你能够用 git reset -pgit checkout -p, or git add -p进入交互模式。github

也能够跳过暂存区域直接从仓库取出文件或者直接提交代码。数据库

  • git commit -a 至关于运行 git add 把全部当前目录下的文件加入暂存区域再运行。git commit.
  • git commit files 进行一次包含最后一次提交加上工做目录中文件快照的提交。而且文件被添加到暂存区域。
  • git checkout HEAD -- files 回滚到复制最后一次提交。

约定

后文中如下面的形式使用图片。vim

绿色的5位字符表示提交的ID,分别指向父节点。分支用橘色显示,分别指向特定的提交。当前分支由附在其上的HEAD标识。 这张图片里显示最后5次提交,ed489是最新提交。 master分支指向这次提交,另外一个maint分支指向祖父提交节点。浏览器

命令详解

Diff

有许多种方法查看两次提交之间的变更。下面是一些示例。缓存

Commit

提交时,git用暂存区域的文件建立一个新的提交,并把此时的节点设为父节点。而后把当前分支指向新的提交节点。下图中,当前分支是master。 在运行命令以前,master指向ed489,提交后,master指向新的节点f0cec并以ed489做为父节点。服务器

即使当前分支是某次提交的祖父节点,git会一样操做。下图中,在master分支的祖父节点maint分支进行一次提交,生成了1800b。 这样,maint分支就再也不是master分支的祖父节点。此时,合并 (或者 衍合) 是必须的。app

若是想更改一次提交,使用 git commit --amend。git会使用与当前提交相同的父节点进行一次新提交,旧的提交会被取消。

另外一个例子是分离HEAD提交,后文讲。

Checkout

checkout命令用于从历史提交(或者暂存区域)中拷贝文件到工做目录,也可用于切换分支。

当给定某个文件名(或者打开-p选项,或者文件名和-p选项同时打开)时,git会从指定的提交中拷贝文件到暂存区域和工做目录。好比,git checkout HEAD~ foo.c会将提交节点HEAD~(即当前提交节点的父节点)中的foo.c复制到工做目录而且加到暂存区域中。(若是命令中没有指定提交节点,则会从暂存区域中拷贝内容。)注意当前分支不会发生变化。

当不指定文件名,而是给出一个(本地)分支时,那么HEAD标识会移动到那个分支(也就是说,咱们“切换”到那个分支了),而后暂存区域和工做目录中的内容会和HEAD对应的提交节点一致。新提交节点(下图中的a47c3)中的全部文件都会被复制(到暂存区域和工做目录中);只存在于老的提交节点(ed489)中的文件会被删除;不属于上述二者的文件会被忽略,不受影响。

若是既没有指定文件名,也没有指定分支名,而是一个标签、远程分支、SHA-1值或者是像master~3相似的东西,就获得一个匿名分支,称做detached HEAD(被分离的HEAD标识)。这样能够很方便地在历史版本之间互相切换。好比说你想要编译1.6.6.1版本的git,你能够运行git checkout v1.6.6.1(这是一个标签,而非分支名),编译,安装,而后切换回另外一个分支,好比说git checkout master。然而,当提交操做涉及到“分离的HEAD”时,其行为会略有不一样,详情见在下面

HEAD标识处于分离状态时的提交操做

HEAD处于分离状态(不依附于任一分支)时,提交操做能够正常进行,可是不会更新任何已命名的分支。(你能够认为这是在更新一个匿名分支。)

一旦此后你切换到别的分支,好比说master,那么这个提交节点(可能)不再会被引用到,而后就会被丢弃掉了。注意这个命令以后就不会有东西引用2eecb

可是,若是你想保存这个状态,能够用命令git checkout -b name来建立一个新的分支。

Reset

reset命令把当前分支指向另外一个位置,而且有选择的变更工做目录和索引。也用来在从历史仓库中复制文件到索引,而不动工做目录。

若是不给选项,那么当前分支指向到那个提交。若是用--hard选项,那么工做目录也更新,若是用--soft选项,那么都不变。

若是没有给出提交点的版本号,那么默认用HEAD。这样,分支指向不变,可是索引会回滚到最后一次提交,若是用--hard选项,工做目录也一样。

若是给了文件名(或者 -p选项), 那么工做效果和带文件名的checkout差很少,除了索引被更新。

Merge

merge 命令把不一样分支合并起来。合并前,索引必须和当前提交相同。若是另外一个分支是当前提交的祖父节点,那么合并命令将什么也不作。 另外一种状况是若是当前提交是另外一个分支的祖父节点,就致使fast-forward合并。指向只是简单的移动,并生成一个新的提交。

不然就是一次真正的合并。默认把当前提交(ed489 以下所示)和另外一个提交(33104)以及他们的共同祖父节点(b325c)进行一次三方合并。结果是先保存当前目录和索引,而后和父节点33104一块儿作一次新提交。

Cherry Pick

cherry-pick命令"复制"一个提交节点并在当前分支作一次彻底同样的新提交。

Rebase

衍合是合并命令的另外一种选择。合并把两个父分支合并进行一次提交,提交历史不是线性的。衍合在当前分支上重演另外一个分支的历史,提交历史是线性的。 本质上,这是线性化的自动的 cherry-pick

上面的命令都在topic分支中进行,而不是master分支,在master分支上重演,而且把分支指向新的节点。注意旧提交没有被引用,将被回收。

要限制回滚范围,使用--onto选项。下面的命令在master分支上重演当前分支从169a6以来的最近几个提交,即2c33a

一样有git rebase --interactive让你更方便的完成一些复杂操做,好比丢弃、重排、修改、合并提交。没有图片体现这些,细节看这里:git-rebase(1)

技术说明

文件内容并无真正存储在索引(.git/index)或者提交对象中,而是以blob的形式分别存储在数据库中(.git/objects),并用SHA-1值来校验。 索引文件用识别码列出相关的blob文件以及别的数据。对于提交来讲,以树(tree)的形式存储,一样用对于的哈希值识别。树对应着工做目录中的文件夹,树中包含的 树或者blob对象对应着相应的子目录和文件。每次提交都存储下它的上一级树的识别码。

若是用detached HEAD提交,那么最后一次提交会被the reflog for HEAD引用。可是过一段时间就失效,最终被回收,与git commit --amend或者git rebase很像。

 

 

Git HEAD detached from XXX (git HEAD 游离) 解决办法

 

 

什么是 HEAD

Git 中的 HEAD 能够理解为一个指针,咱们能够在命令行中输入 cat .git/HEAD 查看当前 HEAD 指向哪儿,通常它指向当前工做目录所在分支的最新提交。

这里写图片描述

当使用 git checkout < branch_name> 切换分支时,HEAD 会移动到指定分支。

这里写图片描述

可是若是使用的是 git checkout < commit id>,即切换到指定的某一次提交,HEAD 就会处于 detached 状态(游离状态)。

这里写图片描述

HEAD 游离状态的利与弊

HEAD 处于游离状态时,咱们能够很方便地在历史版本之间互相切换,好比须要回到某次提交,直接 checkout 对应的 commit id 或者 tag 名便可。

它的弊端就是:在这个基础上的提交会新开一个匿名分支!

这里写图片描述

也就是说咱们的提交是没法可见保存的,一旦切到别的分支,游离状态之后的提交就不可追溯了。

这里写图片描述

解决办法就是新建一个分支保存游离状态后的提交:

这里写图片描述

具体解决操做

  1. git branch -v 查看当前领先多少 
    • 这里写图片描述
    • 4449a91 指向的是 dev1 的最后一次提交
  2. 新建一个 temp 分支,把当前提交的代码放到整个分支 
    • 这里写图片描述
  3. checkout 出要回到的那个分支,这里是 dev1 
    • 这里写图片描述
  4. 而后 merge 刚才建立的临时分支,把那些代码拿回来 
    • 这里写图片描述
  5. git status 查看下合并结果,有冲突就解决 
    • 这里写图片描述
  6. 合并 OK 后就提交到远端 
    • 这里写图片描述
  7. 删除刚才建立的临时分支

    • 这里写图片描述
  8. 查看 Log,当前 HEAD 指向本地 dev1 ,和远端 dev1 一致,OK 了!

    • 这里写图片描述

本地Git与远程仓库进行关联

1.进入本地项目路径,例如 cd /git/test 你的项目路径/
2.输入命令

git init  初始化仓库


3.添加.gitignore文件,将不必的加入版本控制的文件过滤掉,例如

  • index.php(主索引文件)
  • Runtime/*(缓存文件)
  • README.md(readme文件)

这里使用vim .gitignore编辑文件,而后加入如下三行,而后保存退出:wq

index.php
Runtime/*
README.md

4.当前输入git remote命令后,咱们能够看到没有任何东西输出,由于咱们还没添加远程仓库,如今咱们添加远程仓库地址,例如 执行命令git remote add origin 远程仓库地址(这里使用https地址来进行访问),添加后,咱们再试试执行命令git remote看看,终于有输出了

git remote

git remote add origin 远程仓库地址
origin  git@xxx:intelligencevillage.git (fetch)
origin  git@xxx:intelligencevillage.git (push)

5.而后咱们先尝试添加代码到本地仓库,执行git add -A,-A是自动添加所有要上传到仓库的文件,添加完后输入git commit提交到本地仓库。

git add -A    -A是自动添加所有要上传到仓库的文件,添加完后输入
git commit    提交到本地仓库

6.以后使用git push上传到远程仓库,若是是新建分支第一次push,会提示:

git push


英文:

fatal: The current branch develop has no upstream branch.  
To push the current branch and set the remote as upstream, use  
git push --set-upstream origin master  

中文:

fatal: 当前分支 master 没有对应的上游分支。
为推送当前分支并创建与远程上游的跟踪,使用
git push --set-upstream origin master

而后输入git push --set-upstream origin master这行命令,再而后输入用户名和密码,就push成功了。
之后的push就只须要输入git push origin

若是使用SSH访问方式的话,则须要生成ssh公钥才能访问(一下是ssh访问方式)

$ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
# Creates a new ssh key, using the provided email as a label
# Generating public/private rsa key pair.
Enter file in which to save the key (/Users/you/.ssh/id_rsa): [Press enter] //

7.当发现远程仓库已经有内容并提示先执行git pull,将内容进行合并后再上传,在执行git pull的时候,或者会出现

There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details

    git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream-to=origin/<branch> master

也就是指定当前工做目录工做分支,跟远程的仓库,分支之间的连接关系。而后按照提示输入git branch --set-upstream-to=origin/master master与master分支关联,完成后再执行 git pullgit push,打完收工!

git branch --set-upstream-to=origin/master master    与master分支关联指定当前工做目录工做分支,跟远程的仓库,分支之间的连接关系。
git pull 
git push

远程分支

要说分支就必定要从分支产生的最遥远的历史谈起。这一切开始于你用clone命令从远端把代码库的代码拉取到本地开始。这个时候,git自动把这个远端代码库命名为origin并自动建立一个origin/master分支。相对的在本地建立一个叫作master的本地分支。这个时候这两个分支的指针都是指向一个地方的(不一样的push发生的时候,master的指针就会发生变化)。

要建立一个远程分支是很是必要的。也很是的简单。只须要先建立一个本地分支。

git branch 分支名

如 git branch develop

这只是建立了一个叫作develop的分支。若是要使用这个分支,还须要切换到这个分支上:

git checkout 分支名
如 git checkout develop

还有一个更快的方式建立分支,并直接切换到这个分支上:

git checkout -b 分支名
git checkout -b develop

一个命令就把上面的两个命令干得事所有搞定了。

说了半天都是折腾在本地分支(local branch)了。没有离题。远程分支就是本地分支push到远端之后生成的。也就是前面咱们折腾出来的develop分支只要push到远端服务器上就能够了。

git push origin 分支名
git push origin develop

可是,你还须要给你创建起来的远端的和本地的分支设定一个直接的联系。这个时候就须要把你本地的分支变成一个tracking branch。Tracking branch就是一个和远端的分支有直接联系的本地分支。若是你在一个tracking branch里使用git pull命令,那么git自动检测到从哪一个代码库获取代码和哪一个分支执行merge操做。建立tracking branch:

git checkout --track origin/分支名
git checkout --track origin/develop

整个的命令是:

git checkout -b [本地分支名] [远端代码库名称]/[分支名]
//这时会建立一个本地分支名和远端分支名不同的分支

上面的是一个简写的版本。

下面是要给谨慎使用的命令,删除远端分支。

git push origin --delete develop
To https://github.com/xxx/xxxx.git
 - [deleted]         develop

这个时候远端分支就被删除了。

 

平常工做

平常里使用Git的时候就是处理代码的pull,push和merge以及在这个时候遇到的各类问题。

既然有了这么多分支。也许是两个,可是使用Git建立分支的成本真的很是的低,因此有的时候能够是每个大一点的issue就是一个分支。这时候就须要在多个分支之间切换:

git checkout [分支名称]
git checkout develop

天天早晨一到公司首先要作的就是确保你在正确的分支上,而后从git repository上面把代码弄下来。这就要用到pull:

git pull [远端代码库名称] [分支名称]
git pull origin develop

若是你在前一天的晚上忘记push代码或者有其余的人在你push以后push了代码了。那么就会遇到:“冲突”。git会告诉你:

error: Your local changes to "你修改过的文件" would be overwritten by merge. Aborting.

Please commit your changes or stash them before you can merge.

这种状况是编辑文件的冲突

这样的一个Aborting很是的郁闷。好的提示已经告诉咱们该如何解决这个问题了。使用stash。

1. 使用stash命令把本地的代码先存起来。

git stash

这时,你本地的修改已经暂时存起来了。使用命令:git stash list能够看到保存的信息。

2. 而后使用咱们上面说到的pull命令拉取远端库的代码。

git pull

3. 还原暂时保存的本地的修改

git stash pop stash@{0}

手动的解决冲突吧。当你处理好这些冲突的代码以后。

git add [冲突文件名]

而后commit,以后:

当把代码同步的事情弄顺了之后就应该考虑要把本地文件提交到远端代码库了。

git push origin [本地分支名]:[远端分支名]

固然若是你的本地分支名和远端分支名是同样的,那么就只须要git push origin [分支名称]就能够了。 

补充:

1. 有的时候即便你处理完成冲突以后再commit仍是会有问题:

fatal: cannot do a partial commit during a merge.

这个时候:

git commit -i [冲突文件名]

来commit冲突的文件。

2. 这里你还会用到别的命令:

git status // 看看git里的状态,是冲突的有哪些文件等
git show | head // 查看commit进去的是谁、日期等

3. 撤销对某个文件的修改:

git checkout -- [文件名]

 

若是是文件的删除冲突的话

这个时候只要使用

git rm [文件名]

删掉已经被删掉的文件就能够了。

commit以后用git show | head命令查看结果。

 

合并分支

要合并那个分支,好比要把develop的分支合并到master上。那么:

1. 转到master分支上:

git checkout master

2. 开始合并:

git merge develop

在这个命令执行以后就会把develop分支上的代码都合并到master上了。

若是遇到任何冲突

git diff //查看是什么冲突

按照以上提到的解决冲突的方法解决冲突就能够。

撤销一个合并

若是你发现你的本地代码简直是一团糟,须要回到合并以前的状态:

git reset --hard HEAD

本地代码回到合并以前的状态。

或者,你已经把合并后的代码提交,但仍是想把它们撤销:

git reset --hard ORIG_HEAD

可是这个命令某些状况下会很危险,尤为是在你已经把合并后的分支删除以后再使用这个命令。。。

删除不存在对应于远程分支的本地分支

在删除以前首先须要查看一下远端代码库origin下得分支都是什么状况的:

$ git remote show origin
#* remote origin
#  Fetch URL: git@github.com:xxx/xxx.git
#  Push  URL: git@github.com:xxx/xxx.git
#  HEAD branch: master
#  Remote branches:
#    master                 tracked
#    refs/remotes/origin/b1 stale (use 'git remote prune' to remove)
#  Local branch configured for 'git pull':
#    master merges with remote master
#  Local ref configured for 'git push':
#    master pushes to master (up to date)

这时候你会看到这个b1的分支仍是stable的。使用git remote prune origin能够将其从本地代码库中去除。

还有一个更简单的方法:git fetch -p。会在fetch以后删除没有与远程分支对应的本地分支。

重命名远程分支

这个过程很墨迹。由于要先删除远程分支,而后重命名本地分支,而后再提交这个命名好的本地分支到远程分支。

如今有一个devel的分支,要把它重命名为develop。先用git branch -av命令查看分支的情况。这里最重要是肯定好了,你要删除的不是默认分支!以后就能够删除了:

git push --delete origin devel
#To git@github.com:xxx/xxxxxxxx.git
# - [deleted]         devel

重命名本地分支:

git branch -m devel develop

推送本地分支到远端:

$ git push origin develop
#Counting objects: 92, done.
#Delta compression using up to 4 threads.
#Compressing objects: 100% (48/48), done.
#Writing objects: 100% (58/58), 1.38 MiB, done.
#Total 58 (delta 34), reused 12 (delta 5)
#To git@github.com:xxx/xxx-xxxxxx-x.git
# * [new branch]      develop -> develop

查看未推送

查看所有分支的已经commit可是没有push的:

git log --branches --not --remotes

查看所有分支的所有的最近的commit:

git log --branches --not --remotes --simplify-by-decoration --decorate --online

查看某文件的历史记录:

git log my/file.c     #所有历史
git log -n 1 -- my/file.c    #查看最近历史修改

 

常见错误处理

1. non-fast-forward

若是有人比你先push代码到你所在的分支了,那么git就不容许你再嵌入代码到这代码库。

git push origin master
# To https://github.com/USERNAME/REPOSITORY.git
#  ! [rejected]        master -> master (non-fast-forward)
# error: failed to push some refs to 'https://github.com/USERNAME/REPOSITORY.git'
# To prevent you from losing history, non-fast-forward updates were rejected
# Merge the remote changes (e.g. 'git pull') before pushing again.  See the
# 'Note about fast-forwards' section of 'git push --help' for details.

这时候使用fetch和merge的方法解决这个问题:

fetch:

git fetch origin [分支名称]  
merge:

git merge origin [分支名称]

等于

git pull

或者直接pull。pull命令同时执行了这两个命令。

 

1、Git GUI 客户端

  1. Git 客户端下载(Windows)
  2. TortoiseGit 客户端下载(Windows)
  3. Sourcetree 客户端下载(Windows、Mac)
  4. Git Extensions 客户端下载(Windows、Mac、Linux)
  5. SmartGit 客户端下载(Windows、Mac、Linux)
  6. GitEye 客户端下载 (Windows、Mac、Linux)
  7. gitg 客户端下载(Windows、Linux)
  8. ungit 客户端下载(Windows、Mac、Linux)
  9. git-cola 客户端下载(Windows、Mac、Linux)
  10. Tower 客户端下载(Mac)
  11. Gitbox 客户端下载(Mac)
  12. GitUp 客户端下载(Mac)
  13. giggle 客户端下载(Linux)
  14. Pocket Git 客户端下载(Andorid)
  15. Working Copy 客户端下载(IOS)
  16. Git2Go 客户端下载(IOS))
  17. GitDrive 客户端下载(IOS)
  18. 推荐GitKraken https://www.gitkraken.com/

2、Git IDE 插件

  1. Eclipse、Myeclipse 插件下载
  2. Netbeans 插件下载
  3. IntelliJ IDEA 插件下载
  4. Visual Studio 插件下载
  5. Atom 插件下载
  6. Sublime Text 插件下载

3、Git 浏览器插件

  1. Git 浏览器插件下载(Chrome、Firefox、Safari、Opera,支持码云和Github)
  2. Octotree 浏览器插件下载(Chrome,支持Github)
  3. GitLab-TreeView 浏览器插件下载(Chrome,支持GitLab

4、在线 Git 代码托管平台

  1. 码云 Gitee 官网
  2. GitHub 官网
  3. GitLab 官网
  4. Bitbucket 官网

 

Thanks

https://marklodato.github.io/visual-git-guide/index-zh-cn.html#detached 
https://git-scm.com/docs/git-checkout#_detached_head

https://blog.csdn.net/u011240877/article/details/76273335

相关文章
相关标签/搜索