基本概念
我们先来理解下Git 工作区、暂存区和版本库概念
- 工作区:就是你在电脑里能看到的目录。
- 暂存区:英文叫stage, 或index。一般存放在 ".git目录下" 下的index文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。
- 版本库:工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。
下面这个图展示了工作区、版本库中的暂存区和版本库之间的关系:
工作区有一个隐藏目录.git,这个不算工作区,而是Git的版本库。 Git的版本库里存了很多东西,其中最重要的就是称为stage(或者叫index)的暂存区,还有Git为我们自动创建的第一个分支master,以及指向master的一个指针叫HEAD。
我们把文件往Git版本库里添加的时候,是分两步执行的:
第一步是用git add
把文件添加进去,实际上就是把文件修改添加到暂存区;
第二步是用git commit
提交更改,实际上就是把暂存区的所有内容提交到当前分支。
因为我们创建Git版本库时,Git自动为我们创建了唯一一个master
分支,所以,现在,git commit
就是往master
分支上提交更改
配置个人的用户名称和电子邮件地址:
$ git config --global user.name "xxxx"
$ git config --global user.email [email protected]
如果用了 --global 选项,那么更改的配置文件就是位于你用户主目录下的那个,以后你所有的项目都会默认使用这里配置的用户信息。
如果要在某个特定的项目中使用其他名字或者电邮,只要去掉 --global 选项重新配置即可,新的设定保存在当前项目的 .git/config 文件里。
文本编辑器
设置Git默认使用的文本编辑器, 一般可能会是 Vi 或者 Vim。如果你有其他偏好,比如 Emacs 的话,可以重新设置::
$ git config --global core.editor emacs
差异分析工具
还有一个比较常用的是,在解决合并冲突时使用哪种差异分析工具。比如要改用 vimdiff 的话:
$ git config --global merge.tool vimdiff
要检查已有的配置信息,可以使用 git config --list 命令:
初始化一个Git仓库,使用git init
命令。
自己可以在本地创建任意一个目录进入目录中执行
git init 命令即可将此目录设置你的本地的库,这个目录里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。执行此命令后在此目录下会自动生成一个.get文件,其中就
添加文件到Git仓库,分两步:
- 使用命令
git add <file>
,注意,可反复多次使用,添加多个文件; - 使用命令
git commit -m <message>
,完成
用git status
告诉你有文件被修改过,
用git diff
可以查看修改内容。
git push 命令讲解
要关联一个远程库,使用命令git remote add origin git@server-name:path/repo-name.git
;
关联后,使用命令git push -u origin master
第一次推送master分支的所有内容;
此后,每次本地提交后,只要有必要,就可以使用命令git push origin master
推送最新修改;
git push命令用于将本地分支的更新,推送到远程主机。它的格式与git pull命令相仿
git push <远程主机名> <本地分支名>:<远程分支名>
如果省略远程分支名,则表示将本地分支推送与之存在”追踪关系”的远程分支(通常两者同名),如果该远程分支不存在,则会被新建。
1 |
|
上面命令表示,将本地的master分支推送到origin主机的master分支。如果后者不存在,则会被新建。
如果省略本地分支名,则表示删除指定的远程分支,因为这等同于推送一个空的本地分支到远程分支。
1 2 3 |
|
上面命令表示删除origin主机的master分支。
如果当前分支与远程分支之间存在追踪关系,则本地分支和远程分支都可以省略。
1 |
|
上面命令表示,将当前分支推送到origin主机的对应分支。
如果当前分支只有一个追踪分支,那么主机名都可以省略。
1 |
|
如果当前分支与多个主机存在追踪关系,则可以使用-u选项指定一个默认主机,这样后面就可以不加任何参数使用git push。
1 |
|
上面命令将本地的master分支推送到origin主机,同时指定origin为默认主机,后面就可以不加任何参数使用git push了。
不带任何参数的git push,默认只推送当前分支,
还有一种情况,就是不管是否存在对应的远程分支,将本地的所有分支都推送到远程主机,这时需要使用–all选项。
1 |
|
上面命令表示,将所有本地分支都推送到origin主机。
如果远程主机的版本比本地版本更新,推送时Git会报错,要求先在本地做git pull合并差异,然后再推送到远程主机。这时,如果你一定要推送,可以使用–force选项。
1 |
|
上面命令使用–force选项,结果导致在远程主机产生一个”非直进式”的合并(non-fast-forward merge)。除非你很确定要这样做,否则应该尽量避免使用–force选项。
最后,git push不会推送标签(tag),除非使用–tags选项。
1 |
|
其它示例
1.推送本地分支lbranch-1
到新大远程分支rbranch-1
:
$ git push origin lbranch-1:refs/rbranch-1
2.推送lbranch-2
到已有的rbranch-1
,用于补充rbranch-1
:
$ git checkout lbranch-2
$ git rebase rbranch-1
$ git push origin lbranch-2:refs/rbranch-1
3.用本地分支lbranch-3
覆盖远程分支rbranch-1
:
$ git push -f origin lbranch-2:refs/rbranch-1
7.使用push命令,将代码提交到远程对应分支
git push <远程主机名> <本地分支名>:<远程分支名>
git push test master:jenkinsapi
#test 为设置的远程仓库别名,master为本地分支名,jenkinsapi为远程分支名
使用git push origin issue5560:master 就可以把本地分支issue5560推送到远程origin库的master分支了。
如果想把本地的某个分支test提交到远程仓库,并作为远程仓库的master分支,或者作为另外一个名叫test的分支,那么可以这么做。
$ git push origin test:master // 提交本地test分支作为远程的master分支
$ git push origin test:test // 提交本地test分支作为远程的test分支
git pull讲解
命令用于从另一个存储库或本地分支获取并集成(整合)。
git pull
命令的作用是:取回远程主机某个分支的更新,再与本地的指定分支合并,
格式:git pull <远程主机名> <远程分支名>:<本地分支名>
对比
git push <远程主机名> <本地分支名>:<远程分支名>
这里注意,很多时间就是没有注意搞得头晕
1. 如果与当前分支合并,则可省略本地分支名
git pull <远程主机名> <远程分支名>
相当于:git fetch <远程主机名> <远程分支名>
git merge <远程主机名>/<远程分支名>
2. 如果当前分支与远程分支存在追踪关系
git pull <远程主机名>
3. 如果当前分支只有一个追踪关系
git pull
4. 手动建立追踪关系
git branch --set-upstream master origin/next
5. 清理远程已删除本地还存在的分支
git fetch --prune origin
或者 git fetch -p
或者 git pull -p
以下是一些示例 -
$ git pull <远程主机名> <远程分支名>:<本地分支名>
比如,要取回origin
主机的next
分支,与本地的master
分支合并,需要写成下面这样 -
$ git pull origin next:master
如果远程分支(next
)要与当前分支合并,则冒号后面的部分可以省略。上面命令可以简写为:
$ git pull origin next
上面命令表示,取回origin/next
分支,再与当前分支合并。实质上,这等同于先做git fetch
,再执行git merge
。
$ git fetch origin
$ git merge origin/next
在某些场合,Git会自动在本地分支与远程分支之间,建立一种追踪关系(tracking)。比如,在git clone
的时候,所有本地分支默认与远程主机的同名分支,建立追踪关系,也就是说,本地的master
分支自动”追踪”origin/master
分支。
Git也允许手动建立追踪关系。
$ git branch --set-upstream master origin/next
上面命令指定master
分支追踪origin/next
分支。
如果当前分支与远程分支存在追踪关系,git pull
就可以省略远程分支名。
$ git pull origin
上面命令表示,本地的当前分支自动与对应的origin
主机”追踪分支”(remote-tracking branch)进行合并。
如果当前分支只有一个追踪分支,连远程主机名都可以省略。
$ git pull 更新代码的时候尽量使用 git pull --rebase
上面命令表示,当前分支自动与唯一一个追踪分支进行合并。
如果合并需要采用rebase
模式,可以使用–rebase
选项。
$ git pull --rebase <远程主机名> <远程分支名>:<本地分支名>
使用下面的关系区别这两个操作:
git pull = git fetch + git merge
git pull --rebase = git fetch + git rebase
如果你的工作区有修改的文件都但你没有commit,就执行git pull --rebase git 执行git pull –rebase报错误如下:
error: Cannot pull with rebase: You have unstaged changes.
error: Additionally, your index contains uncommitted changes.
原因:如果有未提交的更改,是不能git pull的
解决:
先执行git stash
再执行git pull –rebase
最后再执行git stash pop
解释--
这个命令做了以下内容:
a.把你 commit 到本地仓库的内容,取出来放到暂存区(stash)(这时你的工作区是干净的)
b.然后从远端拉取代码到本地,由于工作区是干净的,所以不会有冲突
c.从暂存区把你之前提交的内容取出来,跟拉下来的代码合并
git fetch和git pull的区别
- git fetch:相当于是从远程获取最新版本到本地,不会自动合并。
$ git fetch origin master
$ git log -p master..origin/master
$ git merge origin/master
以上命令的含义:
- 首先从远程的
origin
的master
主分支下载最新的版本到origin/master
分支上 - 然后比较本地的
master
分支和origin/master
分支的差别 - 最后进行合并
上述过程其实可以用以下更清晰的方式来进行:
$ git fetch origin master:tmp
$ git diff tmp
$ git merge tmp
2. git pull:相当于是从远程获取最新版本并merge
到本地
git pull origin master
上述命令其实相当于git fetch
和 git merge
在实际使用中,git fetch
更安全一些,因为在merge
前,我们可以查看更新情况,然后再决定是否合并。
git pull --rebase,
我们在使用git pull命令的时候,可以使用--rebase参数,即git pull --rebase,这里表示把你的本地当前分支里的每个提交(commit)取消掉,并且把它们临时 保存为补丁(patch)(这些补丁放到".git/rebase"目录中),然后把本地当前分支更新 为最新的"origin"分支,最后把保存的这些补丁应用到本地当前分支上
两者的区别可以用下面的关系式来表示:
git pull = git fetch + git merge
git pull --rebase = git fetch + git rebase
个人建议:在大部分时候合并代码或是更新代码时,推荐使用git rebase --branchname, git pull --rebase;不推荐git merge
一、 Git 常用命令速查
首先 知道git上项目的地址 ,然后挡到本地
git clone git://github.com/schacon/grit.git 从服务器上将代码给拉下来
最常用的 git pull //更新
git add readme 文件名(例如:git add readme demo.php) //代码上传到服务器
git status //查看项目当前状态
git branch 查看本地所有分支
git branch -a 查看所有的分支
git branch -r 查看远程所有分支
git log --decorat 功能差不多的其它命i令(git branch -av)
如果当前本地分支命令非常不规范,分不清本地分支是对应哪个过程分支时,可用此命令查看,当前所处的本地分支对应哪个远程分支,
同样git branch -vv 命令也可以查看当前本地分支与远程分支的关联对应关系
git branch -vv 查看本地分支与远程分支追踪状态
git status 查看当前状态
git commit 提交
git commit -am "init" 提交并且加注释
git remote add origin [email protected]:ndshow
git push origin master 将文件给推到服务器上
git remote show origin 显示远程库origin里的资源
git push origin master:develop 将本地master分支推送到远程origin库中的devolop分支
git push origin master:hb-dev 将本地库与服务器上的库进行关联
git checkout --track origin/dev 切换到远程dev分支
git branch -D master develop 强制删除本地库develop
git branch -d master develop 删除本地库develop
git checkout -b dev 建立一个新的本地分支dev
git merge origin/dev 将远程分支dev与当前分支进行合并
git checkout dev 切换到本地dev分支
git remote show 查看远程库
git add .
git rm 文件名(包括路径) 从git中删除指定文件
git config --list 看所有用户
git ls-files 看已经被提交的
git rm a.a 移除文件(从暂存区和工作区中删除)
git rm --cached a.a 移除文件(只从暂存区中删除)
git rm -f a.a 强行移除修改后文件(从暂存区和工作区中删除)
git rm [file name] 是从暂存区域删除文件,这样以后就不会出现在未跟踪文件清单中了。
如果只是简单地从工作目录中手工删除文件,运行 git status
时就会在 “Changes not staged for commit” 部分(也就是未暂存清单) 看到你git rm 删除的文件操作记录, 然后再运行 git rm
记录此次移除文件的操作,最后提交的时候,该文件就不再纳入版本管理了
另外一种情况是,我们想把文件从 Git 仓库中删除(亦即从暂存区域移除),但仍然希望保留在当前工作目录中。换句话说,仅是从跟踪清单中删除。比如一些大型日志文件或者一堆 .a
编译文件,不小心纳入仓库后,要移除跟踪但不删除文件,以便稍后在 .gitignore
文件中补上,用 --cached
选项即可
git rm --cached readme.txt
git commit --amend 修改上一次的提交信息。
git commit -a 提交当前repos的所有的改变
git add [file name] 添加一个文件到git index
git commit -v 当你用-v参数的时候可以看commit的差异
git commit -m "This is the message describing the commit" 添加commit信息
git commit -a -a是代表add,把所有的change加到git index里然后再commit
git commit -a -v 一般提交命令
git diff 显示工作目录与索引文件之间的差异
git diff –cached显示索引文件与git仓库之间的差异
git diff HEAD 显示工作目录与git仓库之间的差异,
git diff HEAD 显示工作目录与git仓库之间的差异,而git diff HEAD^ 则显示上一次提交之前工作目录与git仓库之间的差异。所以我们在git pull后,
可以通过 git diff HEAD^ 来查看拉下来的文件有那些具体的修改。(此命令与 git diff -p -1 命令作用和结果一样,都是查看最新一个更新的具体修改内容 )
git diff 查看尚未暂存的修改,比较的是工作目录中当前文件和暂存区域快照之间的差异,也就是修改之后还没有暂存起来的变化内容。
git diff --cached 或 $ git diff --staged 查看尚未提交的更新,但已存入暂存区的修改,要查看已经暂存起来的文件和上次提交时的快照之间的差异,
git diff HEAD -- readme.txt
命令可以查看工作区和版本库里面最新版本的区别:
git diff 查看尚未暂存的文件更新了哪些部分 git diff filename
查看尚未暂存的某个文件更新了哪些 git diff –cached
查看已经暂存起来的文件和上次提交的版本之间的差异 git diff –cached filename
查看已经暂存起来的某个文件和上次提交的版本之间的差异 git diff ffd98xxx b8e7xxxxx
查看某两个版本之间的差异 git diff ffd9xxxx:filename b8e7xxx:filename 查看某两个版本的某个文件之间的差异
git stash push 将文件给push到一个临时空间中
git stash pop 将文件从临时空间pop下来
---------------------------------------------------------
git remote add origin [email protected]:username/Hello-World.git
git push origin master 将本地项目给提交到服务器中
-----------------------------------------------------------
git pull 本地与服务器端同步
-----------------------------------------------------------------
git push (远程仓库名) (分支名) 将本地分支推送到服务器上去。
git push origin serverfix:awesomebranch
------------------------------------------------------------------
git fetch 相当于是从远程获取最新版本到本地,不会自动merge
git branch branch_0.1 master 从主分支master创建branch_0.1分支
git branch -m branch_0.1 branch_1.0 将branch_0.1重命名为branch_1.0
git checkout branch_1.0/master 切换到branch_1.0/master分支
git clean命令用来从你的工作目录中删除所有没有tracked过的文件
git clean -n 是一次clean的演习, 告诉你哪些文件会被删除. 记住他不会真正的删除文件, 只是一个提醒
git clean -f 删除当前目录下所有没有track过的文件. 他不会删除.gitignore文件里面指定的文件夹和文件, 不管这些文件有没有被track过
git clean -f <path> 删除指定路径下的没有被track过的文件
git clean -df 删除当前目录下没有被track过的文件和文件夹 git clean -xf 删除当前目录下所有没有track过的文件. 不管他是否是.gitignore文件里面指定的文件夹和文件
git reset --hard和git clean -f是一对好基友. 结合使用他们能让你的工作目录完全回退到最近一次commit的时候
git log 看你commit的日志
git log -- file 查看某一个文件的修改记录,如SystemUI.java: git log -- SystemUI.java
git log -p filename 可以显示该文件每次提交的diff
git log -p -2 用 -2
则仅显示最近的两次更新
git log --graph命令可以看到分支合并图
git log --stat --stat
,仅显示简要的增改行数统计
git log --pretty=oneline oneline
将每个提交放在一行显示,这在提交数很大时非常有用。另外还有 short
,full
和 fuller
git log --decorat 功能差不多的其它命i令(git branch -av)
git log --author=xxxx 过滤某人的提交记录,
你也可以用正则表达式来创建更复杂的检索。比如,下面这个命令检索名叫Mary或John的作者的提交。
git log --author="John\|Mary"
git commit -a -m "log_message" (-a是提交所有改动,-m是加入log信息) 本地修改同步至服务器端 :
git commit --amend 有时候我们提交完了才发现漏掉了几个文件没有加,或者提交信息写错了。想要撤消刚才的提交操作,可以使用
如果刚才提交时忘了暂存某些修改,可以先补上暂存操作,然后再运行 --amend
提交:
$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend
git reset HEAD <file>... 撤销从工作目录中提交gita add到暂存区域的 如不小心用 git add .
全加到了暂存区域。该如何撤消暂存其中的一个文件呢,
git checkout file取消到工作目录中文件的修改
git reset --hard HEAD^ 回退到上一个版本,用HEAD
表示当前版本,也就是最新的提交1094adb...
(注意我的提交ID和你的肯定不一样),上一个版本就是HEAD^
,上上一个版本就是HEAD^^
,当然往上100个版本写100个^
比较容易数不过来,所以写成HEAD~100
git reset --hard 1094a 后面的HASH码 可以通过执行git log查看,一般写前面四位即可,当然你也可以完整的
先在本地回退到相应的版本:
git reset --hard <版本号>
// 注意使用 --hard 参数会抛弃当前工作区的修改
// 使用 --soft 参数的话会回退到之前的版本,但是保留当前工作区的修改,可以重新提交
【本地代码库回滚】:
git reset --hard commit-id :回滚到commit-id,讲commit-id之后提交的commit都去除
git reset --hard HEAD~3:将最近3次的提交回滚
【远程代码库回滚】:
git reset --hard HEAD^ | git reset --hard <版本号> 先回滚本地的代码
git push origin master --force 会提示本地的版本落后于远端的版本 所以得加参数--force 强制提交
git revert 是生成一个新的提交来撤销某次提交,此次提交之前的commit都会被保留
git reset 是回到某次提交,提交及之前的commit都会被保留,但是此次之后的修改都会被退回到暂存区
git reflog
如果你回退到了某个版本 但最后又觉得之前某一新版本才是最理想的版本,想恢复到新版本怎么办?而且找不到新版本的commit id怎么办?Git提供了一个命令 git reflog
用来记录你的每一次命令,要重返未来,用git reflog
查看命令历史,以便确定要回到未来的哪个版本。
3、git show comit_id filename
可以查看某次提交中的某个文件变化
4、git show commit_id
查看某次提交
5、gitk --follow filename
以图形化界面的方式显示修改列表
git apply 应用补丁
远程 分支问题:
跟踪远程分支
1)如果远程新建了一个分支,本地没有该分支,可以用git checkout --track origin/branch_name,这时候本地会新建一个分支名叫branch_name,会自动跟踪远程的同名分支branch_name。
2)用上面中方法,得到的分支名永远和远程的分支名一样,如果想新建一个本地分支不同名字,同时跟踪一个远程分支可以利用。
git checkout -b new_branch_name branch_name,这条指令本来是根据一个branch_name分支分出一个本地分支new_branch_name,但是如果所根据的分支branch_name是一个远程分支名,那么本地的分支会自动的track远程分支。建议跟踪分支和被跟踪远程分支同名。
总结:一般我们就用
git push --set-upstream origin branch_name 来在远程创建一个与本地branch_name同名的分支并跟踪;
git checkout --track origin/branch_name 来在本地创建一个与branch_name同名分支跟踪远程分支
Git merge 不同的branch
Git的优势是可以创建不同的branch,然后在每个branch上开发。那么问题是:如果不同的branch之间需要做同步,比如sourceBranch上做的修改也需要同步到targetBranch,改怎么做?
A). 如果一个branchA (targetBranch)是有远程Git server管理的,另一个branchB (sourceBranch)是自己本地的,即把sourceBranch的修改merge到targetBranch上:
1. cd <your workspace>
2. git branch //假定现在所在的branch是targetBranch,并最好保证没有未提交的修改,并且已经更新到最新
3. git checkout -b branchB //创建一个本地的sourceBranch并切换到sourceBranch
4. git commit //把sourceBranch上做的修改先提交
5. git checkout branchA //切换回targetBranch
6. git merge --no-ff branchB //把sourceBranch的修改merge到targetBranch。注意:建议merge的时候总是用 --no-ff 选项
7. git status //保证现在workspace是干净的
8. git push origin branchA //push到远程,如果远程有新的修改,先做一下git pull
B). 如果两个branch都是远程管理的,想把branchB (sourceBranch)的内容同步到branchA (targetBranch)上
1. cd <your workspace>
2. git branch //假定现在所在的branch是branchA (targetBranch),并最好保证没有未提交的修改,并且已经更新到最新
3. git checkout branchB //确保同一个workspace能在不同的branch直接切换,即保证 .git/config里 [remote "origin"] 的内容是 fetch = +refs/heads/*:refs/remotes/origin/*
4. git merge branchA //先把targetBranch的修改merge到sourceBranch上,这样有冲突可以在sourceBranch上先解决,保证之后再merge回targetBranch的时候容易处理,targetBranch不再有冲突
5. 解决conflicts如果merge的结果里有显示conflicts
6. git commit //解决冲突后先commit到branchB
7. git checkout branchA //切换到targetBranch
8. git merge --no-ff branchB //建议merge的时候总是用 --no-ff 选项
9. git push origin branchA //把sourceBranch的修改merge到targetBranch之后,push到远程的targetBranch
做git patch文件
先首先先通过git log 查看有哪一些commit,然后在你要把提交的前一个 commitid,git format-patch commitid,那你的这次提交就是相应对前一次commit 生成的
1 使用git format-patch生成所需要的patch:
当前分支所有超前master的提交:
git format-patch -M master
某次提交以后的所有patch:
git format-patch 4e16 --4e16指的是commit名
从根到指定提交的所有patch:
git format-patch --root 4e16
某两次提交之间的所有patch:
git format-patch 365a..4e16 --365a和4e16分别对应两次提交的名称
某次提交(含)之前的几次提交:
git format-patch –n 07fe --n指patch数,07fe对应提交的名称
故,单次提交即为:
git format-patch -1 07fe
git format-patch生成的补丁文件默认从1开始顺序编号,并使用对应提交信息中的第一行作为文件名。如果使用了-- numbered-files选项,则文件名只有编号,不包含提交信息;如果指定了--stdout选项,可指定输出位置,如当所有patch输出到一个文件;可指定-o <dir>指定patch的存放目录;
2应用patch:
先检查patch文件:git apply --stat newpatch.patch
检查能否应用成功:git apply --check newpatch.patch
打补丁:git am --signoff < newpatch.patch