git详细教程


1 Git详细教程

 


1.1 Git简介

 


1.1.1 Git是何方神圣?

 

Git是用C语言开发的分布版本控制系统。版本控制系统能够保留一个文件集合的历史记录,并能回滚文件集合到另外一个状态(历史记录状态)。另外一个状态能够是不一样的文件,也能够是不一样的文件内容。举个例子,你能够将文件集合转换到两天以前的状态,或者你能够在生产代码和实验性质的代码之间进行切换。文件集合每每被称做是“源代码”。在一个分布版本控制系统中,每一个人都有一份完整的源代码(包括源代码全部的历史记录信息),并且能够对这个本地的数据进行操做。分布版本控制系统不须要一个集中式的代码仓库。html

 

当你对本地的源代码进行了修改,你能够标注他们跟下一个版本相关(将他们加到index中),而后提交到仓库中来(commit)。Git保存了全部的版本信息,因此你能够转换你的源代码到任何的历史版本。你能够对本地的仓库进行代码的提交,而后与其余的仓库进行同步。你可使用Git来进行仓库的克隆(clone)操做,完整的复制一个已有的仓库。仓库的全部者能够经过push操做(推送变动到别处的仓库)或者Pull操做(从别处的仓库拉取变动)来同步变动。git

 

Git支持分支功能(branch)。若是你想开发一个新的产品功能,你能够创建一个分支,对这个分支的进行修改,而不至于会影响到主支上的代码。github

 

Git提供了命令行工具;这个教程会使用命令行。你也能够找到图形工具,譬如与Eclipse配套的EGit工具,可是这些都不会在这个教程中进行描述。算法


1.1.2 重要的术语

 

Git 术语ubuntu

 
术语 定义
仓库 一个仓库包括了全部的版本信息、全部的分支和标记信息.
Repository 在Git中仓库的每份拷贝都是完整的。仓库让你能够从中
  取得你的工做副本。
  一个分支意味着一个独立的、拥有本身历史信息的代码线
分支 (code line)。你能够从已有的代码中生成一个新的分支
Branches ,这个分支与剩余的分支彻底独立。默认的分支每每是叫
  master。用户能够选择一个分支,选择一个分支叫作
  checkout.
标记 一个标记指的是某个分支某个特定时间点的状态。经过标
Tags 记,能够很方便的切换到标记时的状态,例如2009年1月25
  号在testing分支上的代码状态
提交 提交代码后,仓库会建立一个新的版本。这个版本能够在
Commit 后续被从新得到。每次提交都包括做者和提交者,做者和
  提交者能够是不一样的人
URL URl用来标识一个仓库的位置
  用来表示代码的一个版本状态。Git经过用SHA1 hash算法
修订 表示的id来标识不一样的版本。每个 SHA1 id都是160位长
Revision ,16进制标识的字符串.最新的版本能够经过HEAD来获取.
  以前的版本能够经过"HEAD~1"来获取,以此类推。


1.1.3 索引

 

Git 须要将代码的变化显示的与下一次提交进行关联。举个例子,若是你对一个文件继续了修改,而后想将这些修改提交到下一次提交中,你必须将这个文件提交到索引中,经过git add file命令。这样索引能够保存全部变化的快照。安全

 

新增的文件老是要显示的添加到索引中来。对于那些以前已经提交过的文件,能够在commit命令中使用-a 选项达到提交到索引的目的。服务器

 

1.2 Git安装

 

在Ubuntu上,你能够经过apt来安装git命令行工具网络

 

sudo apt-get install git-core

 

对于其余的Linux版本,请查看相关的软件包安装工具使用方法。msysgit项目提供了Windows版本的Git,地址是http://code.google.com/p/msysgit/并发


1.3 Git配置

 

你能够在.gitconfig文件中防止git的全局配置。文件位于用户的home目录。上述已经提到每次提交都会保存做者和提交者的信息,这些信息均可以保存在全局配置中。后续将会介绍配置用户信息、高亮显示和忽略特定的文件。app

 

1.3.1 用户信息

 

经过以下命令来配置用户名和Email

git config --global user.name "Example Surname"

git config --global user.email "your.email@gmail.com"
# Set default so that all changes are always pushed to the repository
git config --global push.default "matching"

 

获取Git配置信息,执行如下命令:

git config --list


1.3.2 高亮显示

如下命令会为终端配置高亮

git config --global color.status auto
git config --global color.branch auto


1.3.3 忽略特定的文件

能够配置Git忽略特定的文件或者是文件夹。这些配置都放在.gitignore文件中。这个文件能够存在于不一样的文件夹中,能够包含不一样的文件匹配模式。为了让Git忽略bin文件夹,在主目录下放置.gitignore文件,其中内容为bin。

同时Git也提供了全局的配置,core.excludesfile。


1.3.4 使用.gitkeep来追踪空的文件夹

Git会忽略空的文件夹。若是你想版本控制包括空文件夹,根据惯例会在空文件夹下放置.gitkeep文件。其实对文件名没有特定的要求。一旦一个空文件夹下有文件后,这个文件夹就会在版本控制范围内。


1.4 开始操做Git

后续将经过一个典型的Git工做流来学习。在这个过程当中,你会建立一些文件、建立一个本地的Git仓库、提交你的文件到这个仓库中。这以后,你会克隆一个仓库、在仓库之间经过pull和push操做来交换代码的修改。注释(以#开头)解释了命令的具体含义,让咱们打开命令行开始操做吧。


1.4.1 建立内容

下面建立一些文件,它们会被放到版本控制之中

<span style="color: rgb(255, 127, 36);">#</span><span style="color: rgb(255, 127, 36);">Switch to home
</span><span style="color: rgb(176, 196, 222);">cd</span> ~/
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Create a directory
</span>mkdir ~/repo01
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Switch into it
</span><span style="color: rgb(176, 196, 222);">cd</span> repo01
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Create a new directory
</span>mkdir datafiles
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Create a few files
</span>touch test01
touch test02
touch test03
touch datafiles/data.txt
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Put a little text into the first file
</span>ls >test01


1.4.2 建立仓库、添加文件和提交更改

每一个Git仓库都是放置在.git文件夹下.这个目录包含了仓库的全部历史记录,.git/config文件包含了仓库的本地配置。

如下将会建立一个Git仓库,添加文件倒仓库的索引中,提交更改。

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Initialize the local Git repository
</span>git init
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Add all (files and directories) to the Git repository
</span>git add .
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Make a commit of your file to the local repository
</span>git commit -m <span style="color: rgb(255, 160, 122);">"Initial commit"</span>
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Show the log file
</span>git log


1.4.3 diff命令与commit更改

经过git diff命令,用户能够查看更改。经过改变一个文件的内容,看看gitdiff命令输出什么,而后提交这个更改到仓库中

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Make some changes to the file
</span><span style="color: rgb(176, 196, 222);">echo</span> <span style="color: rgb(255, 160, 122);">"This is a change"</span> > test01
<span style="color: rgb(176, 196, 222);">echo</span> <span style="color: rgb(255, 160, 122);">"and this is another change"</span> > test02

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Check the changes via the diff command 
</span>git diff

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Commit the changes, -a will commit changes for modified files
</span><span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">but will not add automatically new files
</span>git commit -a -m <span style="color: rgb(255, 160, 122);">"These are new changes"</span>


1.4.4 Status, Diff 和 Commit Log

下面会向你展现仓库现有的状态以及过往的提交历史

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Make some changes in the file
</span><span style="color: rgb(176, 196, 222);">echo</span> <span style="color: rgb(255, 160, 122);">"This is a new change"</span> > test01
<span style="color: rgb(176, 196, 222);">echo</span> <span style="color: rgb(255, 160, 122);">"and this is another new change"</span> > test02

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">See the current status of your repository 
</span><span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">(which files are changed / new / deleted)
</span>git status
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Show the differences between the uncommitted files 
</span><span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">and the last commit in the current branch
</span>git diff

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Add the changes to the index and commit
</span>git add . && git commit -m <span style="color: rgb(255, 160, 122);">"More chaanges - typo in the commit message"</span>

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Show the history of commits in the current branch
</span>git log
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">This starts a nice graphical view of the changes
</span>gitk --all


1.4.5 更正提交的信息 - git amend

经过git amend命令,咱们能够修改最后提交的的信息。上述的提交信息中存在错误,下面会修改这个错误。

git commit --amend -m "More changes - now correct"


1.4.6 删除文件

若是你删除了一个在版本控制之下的文件,那么使用git add .不会在索引中删除这个文件。须要经过带-a选项的git commit命令和-A选项的git add命令来完成

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Create a file and put it under version control
</span>touch nonsense.txt
git add . && git commit -m <span style="color: rgb(255, 160, 122);">"a new file has been created"</span>
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Remove the file
</span>rm nonsense.txt
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Try standard way of committing -> will not work 
</span>git add . && git commit -m <span style="color: rgb(255, 160, 122);">"a new file has been created"</span>
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Now commit with the -a flag
</span>git commit -a -m <span style="color: rgb(255, 160, 122);">"File nonsense.txt is now removed"</span>
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Alternatively you could add deleted files to the staging index via
</span>git add -A . 
git commit -m <span style="color: rgb(255, 160, 122);">"File nonsense.txt is now removed"</span>


1.5 远端仓库(remote repositories)

 


1.5.1 设置一个远端的Git仓库

 

咱们将建立一个远端的Git仓库。这个仓库能够存储在本地或者是网络上。

 

远端Git仓库和标准的Git仓库有以下差异:一个标准的Git仓库包括了源代码和历史信息记录。咱们能够直接在这个基础上修改代码,由于它已经包含了一个工做副本。可是远端仓库没有包括工做副本,只包括了历史信息。可使用–bare选项来建立一个这样的仓库。

 

为了方便起见,示例中的仓库建立在本地文件系统上

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Switch to the first repository
</span><span style="color: rgb(176, 196, 222);">cd</span> ~/repo01
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">
</span>git clone --bare . ../remote-repository.git

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Check the content, it is identical to the .git directory in repo01
</span>ls ~/remote-repository.git


1.5.2 推送更改到其余的仓库

 

作一些更改,而后将这些更改从你的第一个仓库推送到一个远端仓库 

 

cd ~/repo01

echo "Hello, hello. Turn your radio on" > test01echo "Bye, bye. Turn your radio off" > test02

git commit -a -m "Some changes"

git push ../remote-repository.git

 

1.5.3 添加远端仓库

 

除了经过完整的URL来访问Git仓库外,还能够经过git remote add命令为仓库添加一个短名称。当你克隆了一个仓库之后,origin表示所克隆的原始仓库。即便咱们从零开始,这个名称也存在。

 

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Add ../remote-repository.git with the name origin
</span>git remote add origin ../remote-repository.git 

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Again some changes
</span><span style="color: rgb(176, 196, 222);">echo</span> <span style="color: rgb(255, 160, 122);">"I added a remote repo"</span> > test02
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Commit
</span>git commit -a -m <span style="color: rgb(255, 160, 122);">"This is a test for the new remote origin"</span>
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">If you do not label a repository it will push to origin
</span>git push origin


1.5.4 显示已有的远端仓库

 

经过如下命令查看已经存在的远端仓库

# Show the existing defined remote repositories
git remote


1.5.5 克隆仓库

经过如下命令在新的目录下建立一个新的仓库

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Switch to home
</span><span style="color: rgb(176, 196, 222);">cd</span> ~
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Make new directory
</span>mkdir repo02

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Switch to new directory
</span>
<span style="color: rgb(176, 196, 222);">cd</span> ~/repo02
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Clone
</span>git clone ../remote-repository.git .


1.5.6 拉取(Pull)更改

经过拉取,能够从其余的仓库中获取最新的更改。在第二个仓库中,作一些更改,而后将更改推送到远端的仓库中。而后第一个仓库拉取这些更改

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Switch to home
</span><span style="color: rgb(176, 196, 222);">cd</span> ~

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Switch to second directory
</span><span style="color: rgb(176, 196, 222);">cd</span> ~/repo02
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Make changes
</span><span style="color: rgb(176, 196, 222);">echo</span> <span style="color: rgb(255, 160, 122);">"A change"</span> > test01
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Commit
</span>git commit -a -m <span style="color: rgb(255, 160, 122);">"A change"</span>
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Push changes to remote repository
</span><span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Origin is automatically maintained as we cloned from this repository
</span>git push origin
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Switch to the first repository and pull in the changes
</span><span style="color: rgb(176, 196, 222);">cd</span> ~/repo01
git pull ../remote-repository.git/
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Check the changes
</span>less test01


1.5.7 还原更改

若是在你的工做副本中,你建立了不想被提交的文件,你能够丢弃它。

# Create a new file with content
touch test04
echo "this is trash" > test04

# Make a dry-run to see what would happen
# -n is the same as --dry-run 
git clean -n

# Now delete
git clean -f

你能够提取老版本的代码,经过提交的ID。git log命令能够查看提交ID 

# Switch to home
cd ~/repo01
# Get the log
git log

# Copy one of the older commits and checkout the older revision via  译者注:checkout 后加commit id就是把commit的内容复制到index和工做副本中 
git checkout commit_name

 

若是你还未把更改加入到索引中,你也能够直接还原全部的更改

<span style="color: rgb(255, 127, 36);">#</span><span style="color: rgb(255, 127, 36);">Some nonsense change
</span><span style="color: rgb(176, 196, 222);">echo</span> <span style="color: rgb(255, 160, 122);">"nonsense change"</span> > test01
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Not added to the staging index. Therefore we can 
</span><span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">just checkout the old version
</span><span style="color: rgb(255, 127, 36);">#</span><span style="color: rgb(255, 127, 36);">译者注:checkout后若是没有commit id号,就是从index中拷贝数据到工做副本,不涉及commit部分的改变
</span>git checkout test01
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Check the result
</span>cat test01
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Another nonsense change
</span><span style="color: rgb(176, 196, 222);">echo</span> <span style="color: rgb(255, 160, 122);">"another nonsense change"</span> > test01
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">We add the file to the staging index
</span>git add test01
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Restore the file in the staging index
</span><span style="color: rgb(255, 127, 36);">#</span><span style="color: rgb(255, 127, 36);">译者注:复制HEAD所指commit的test01文件到index中
</span>git reset HEAD test01
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Get the old version from the staging index
</span><span style="color: rgb(255, 127, 36);">#</span><span style="color: rgb(255, 127, 36);">译者注:复制index中test01到工做副本中
</span>git checkout test01
<span style="color: rgb(255, 127, 36);">#</span><span style="color: rgb(255, 127, 36);">译者注,以上两条命令能够合并为git checkout HEAD test01
</span>
也能够经过revert命令进行还原操做 

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Revert a commit
</span>git revert commit_name

 

即便你删除了一个未添加到索引和提交的文件,你也能够还原出这个文件

<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Delete a file
</span>rm test01
<span style="color: rgb(255, 127, 36);"># </span><span style="color: rgb(255, 127, 36);">Revert the deletion
</span>git checkout test01

 

若是你已经添加一个文件到索引中,可是未提交。能够经过git resetfile 命令将这个文件从索引中删除

// Create a file
touch incorrect.txt
// Accidently add it to the index
git add .
// Remove it from the index
git reset incorrect.txt
// Delete the file
rm incorrect.txt

 

若是你删除了文件夹且还没有提交,能够经过如下命令来恢复这个文件夹 。译者注:即便已经提交,也能够还原

git checkout HEAD -- your_dir_to_restore

 

译者注:checkout和reset这两个命令的含义是不一样的,能够参阅这篇文章http://marklodato.github.com/visual-git-guide/index-en.html


1.5.8 标记

Git可使用对历史记录中的任一版本进行标记。这样在后续的版本中就能轻松的找到。通常来讲,被用来标记某个发行的版本。能够经过git tag命令列出全部的标记,经过以下命令来建立一个标记和恢复到一个标记

git tag version1.6 -m 'version 1.6'      
git checkout <tag_name>


1.6 分支、合并

 
 

1.6.1 分支

 

经过分支,能够创造独立的代码副本。默认的分支叫master。Git消耗不多的资源就能建立分支。Git鼓励开发人员多使用分支

 

下面的命令列出了全部的本地分支,当前所在的分支前带有*号

git branch 

 

若是你还想看到远端仓库的分支,可使用下面的命令

git branch -a

 

能够经过下面的命令来建立一个新的分支

# Syntax: git branch <name> <hash>
# <hash> in the above is optional 
# if not specified the last commit will be used
# If specified the corresponding commit will be used
git branch testing
# Switch to your new branch
git checkout testing
# Some changes
echo "Cool new feature in this branch" > test01
git commit -a -m "new feature"
# Switch to the master branch
git checkout master
# Check that the content of test01 is the old one
cat test01


1.6.2 合并

 

经过Merge咱们能够合并两个不一样分支的结果。Merge经过所谓的三路合并来完成。分别来自两个分支的最新commit和两个分支的最新公共commit.能够经过以下的命令进行合并

# Syntax: git merge <branch-name>
git merge testing

 

一旦合并发生了冲突,Git会标志出来,开发人员须要手工的去解决这些冲突。解决冲突之后,就能够将文件添加到索引中,而后提交更改


1.6.3 删除分支

 

删除分支的命令以下:

#Delete branch testing
git branch -d testing
# Check if branch has been deleted
git branch


1.6.4 推送(push)一个分支到远端仓库

 

默认的,Git只会推送匹配的分支的远端仓库。这意味在使用git push命令默认推送你的分支以前,须要手工的推送一次这个分支。

# Push testing branch to remote repository
git push origin testing

# Switch to the testing branch
git checkout testing

# Some changes
echo "News for you" > test01
git commit -a -m "new feature in branch"

# Push all including branch
git push

经过这种方式,你能够肯定哪些分支对于其余仓库是可见的,而哪些只是本地的分支


1.7 解决合并冲突

 

若是两个不一样的开发人员对同一个文件进行了修改,那么合并冲突就会发生。而Git没有智能到自动解决合并两个修改。

 

在这一节中,咱们会首先制造一个合并冲突,而后解决它,并应用到Git仓库中。

 

下面会产生一个合并冲突

 

# Switch to the first directory
cd ~/repo01
# Make changes
touch mergeconflict.txt
echo "Change in the first repository" > mergeconflict.txt
# Stage and commit
git add . && git commit -a -m "Will create merge conflict 1"

# Switch to the second directory
cd ~/repo02
# Make changes
touch mergeconflict.txt
echo "Change in the second repository" > mergeconflict.txt
# Stage and commit
git add . && git commit -a -m "Will create merge conflict 2"
# Push to the master repository
git push

# Now try to push from the first directory
# Switch to the first directory
cd ~/repo01
# Try to push --> you will get an error message
git push
# Get the changes
git pull origin master

 

Git将冲突放在收到影响的文件中,文件内容以下:

<<<<<<< HEAD
Change in the first repository
=======
Change in the second repository
>>>>>>> b29196692f5ebfd10d8a9ca1911c8b08127c85f8

 

上面部分是你的本地仓库,下面部分是远端仓库。如今编辑这个文件,而后commit更改。另外的,你可使用git mergetool命令

# Either edit the file manually or use 
git mergetool
# You will be prompted to select which merge tool you want to use
# For example on Ubuntu you can use the tool "meld"
# After  merging the changes manually, commit them
git commit -m "merged changes"


1.8 变基(Rebase)

 
 

1.8.1 在同一分支中应用Rebase Commit

 

经过rebase命令能够合并多个commit为一个。这样用户push更改到远端仓库的时候就能够先修改commit历史

 

接下来咱们将建立多个commit,而后再将它们rebase成一个commit

 

# Create a new file
touch rebase.txt

# Add it to git
git add . && git commit -m "rebase.txt added to index"

# Do some silly changes and commit
echo "content" >> rebase.txt
git add . && git commit -m "added content"
echo " more content" >> rebase.txt
git add . && git commit -m "added more content"
echo " more content" >> rebase.txt
git add . && git commit -m "added more content"
echo " more content" >> rebase.txt
git add . && git commit -m "added more content"
echo " more content" >> rebase.txt
git add . && git commit -m "added more content"
echo " more content" >> rebase.txt
git add . && git commit -m "added more content"

# Check the git log message
git log

咱们合并最后的七个commit。你能够经过以下的命令交互的完成

git rebase -i HEAD~7

这个命令会打开编辑器让你修改commit的信息或者 squash/ fixup最后一个信息.Squash会合并commit信息而fixup会忽略commit信息(待理解)

1.8.2 Rebasing多个分支

你也能够对两个分支进行rebase操做。以下所述,merge命令合并两个分支的更改。rebase命令为一个分支的更改生成一个补丁,而后应用这个补丁到另外一分支中

使用merge和rebase,最后的源代码是同样的,可是使用rebase产生的commit历史更加的少,并且历史记录看上去更加的线性

# Create new branch 
git branch testing
# Checkout the branch
git checkout testing
# Make some changes
echo "This will be rebased to master" > test01
# Commit into testing branch
git commit -a -m "New feature in branch"
# Rebase the master
git rebase master


1.8.3 Rebase最佳实践

在push更改到其余的Git仓库以前,咱们须要仔细检查本地分支的commit历史

 

在Git中,你可使用本地的commit。开发人员能够利用这个功能方便的回滚本地的开发历史。可是在push以前,须要观察你的本地分支历史,是否其中有些commit历史对其余用户来讲是无关的

 

若是全部的commit历史都跟同一个功能有关,不少状况下,你须要rebase这些commit历史为一个commit历史。

 

交互性的rebase主要就是作重写commit历史的任务。这样作是安全的,由于commit尚未被push到其它的仓库。这意味着commit历史只有在被push以前被修改。

 

若是你修改而后push了一个已经在目标仓库中存在的commit历史,这看起来就像是你实现了一些别人已经实现的功能


1.8.4 建立和应用补丁

 

一个补丁指的是一个包含对源代码进行修改的文本文件。你能够将这个文件发送给某人,而后他就能够应用这个补丁到他的本地仓库。

 

下面会建立一个分支,对这个分支所一些修改,而后建立一个补丁,并应用这个补丁到master分支

 

# Create a new branch
git branch mybranch
# Use this new branch
git checkout mybranch
# Make some changes
touch test05
# Change some content in an existing file
echo "New content for test01" >test01
# Commit this to the branch
git add .
git commit -a -m "First commit in the branch"

# Create a patch --> git format-patch master
git format-patch origin/master
# This created patch 0001-First-commit-in-the-branch.patch

# Switch to the master
git checkout master

# Apply the patch
git apply 0001-First-commit-in-the-branch.patch
# Do your normal commit in the master 
git add .
git commit -a -m "Applied patch"

# Delete the patch 
rm 0001-First-commit-in-the-branch.patch


1.9 定义同名命令

 

Git容许你设定你本身的Git命令。你能够给你本身经常使用的命令起一个缩写命令,或者合并几条命令道一个命令上来。

 

下面的例子中,定义了git add-commit 命令,这个命令合并了git add . -A 和git commit -m 命令。定义这个命令后,就可使用git add-commit -m"message" 了.

 

git config --global alias.add-commit '!git add . -A && git commit'

可是很是不幸,截止写这篇文章以前,定义同名命令在msysGit中尚未支持。同名命令不能以!开始。


1.10 放弃跟踪文件

 

有时候,你不但愿某些文件或者文件夹被包含在Git仓库中。可是若是你把它们加到.gitignore文件中之后,Git会中止跟踪这个文件。可是它不会将这个文件从仓库中删除。这致使了文件或者文件夹的最后一个版本仍是存在于仓库中。为了取消跟踪这些文件或者文件夹,你可使用以下的命令

 

# Remove directory .metadata from git repo
git rm -r --cached .metadata
# Remove file test.txt from repo
git rm --cached test.txt

这样作不会将这些文件从commit历史中去掉。若是你想将这些文件从commit历史中去掉,能够参考git filter-branch命令


1.11 其余有用的命令

 

下面列出了在平常工做中很是有用的Git命令

 

有用的Git命令

 

 
命令 描述
git blame filename 谁建立了或者是修改了这个文件
git checkout -b mybranch 以上上个commit信息为起点,建立一条
master~1 新的分支


1.12 安装Git服务

 

如上所述,咱们的操做不须要Git服务。我能够只使用文件系统或者是Git仓库的提供者,像Github或Bitbucket。可是,有时候,拥有一个本身的服务是比较方便的,在ubuntu下安装一个服务相对来讲是比较容易的

 

肯定你已经安装了ssh

apt-get install ssh

 

若是你尚未安装Git服务,安装它

sudo apt-get install git-core

 

添加一个名为git的用户

sudo adduser git

 

而后使用git用户进行登录,建立一个空的仓库

# Login to server
# to test use localhost
ssh git@IP_ADDRESS_OF_SERVER

# Create repository
git init --bare example.git

 

如今你就能够向远端的仓库提交变动了

mkdir gitexample
cd gitexample
git init
touch README
git add README
git commit -m 'first commit'
git remote add origin git@IP_ADDRESS_OF_SERVER:example.git
git push origin master


1.13 在线的远端仓库

 
 

1.13.1 克隆远端仓库

 

Git支持远端的操做。Git支持多种的传输类型,Git自带的协议就叫作git。下面的的命令经过git协议从克隆一个仓库

git clone git@github.com:vogella/gitbook.git

 

一样的,你能够经过http协议来克隆仓库

# The following will clone via HTTP 
git clone http://vogella@github.com/vogella/gitbook.git


1.13.2 添加远端仓库

若是你克隆了一个远端仓库,那么原先的仓库就叫作origin

你能够push修改到origin中,经过 git push origin 命令. 固然,push到一个远端的仓库须要对仓库的写权限

你能够经过git remote add name gitrepo 命令添加多个仓库。例如,你能够经过http协议再次添加以前clone过来的仓库:

// Add the https protocol 
git remote add githttp https://vogella@github.com/vogella/gitbook.git


1.13.3 经过http和代理服务器进行远端操做

若是你的防火墙屏蔽了出http之外的全部协议,那么使用http协议来获取仓库是很是好的方法。.

Git一样支持经过代理服务器使用http协议。下面的Git命令会展现这一点。你能够为全部的程序设置代理服务器或者只是为Git服务提供。

下面的例子用到了环境变量

# Linux
export http_proxy=http://proxy:8080
# On Windows
# Set http_proxy=http://proxy:8080 
git clone http://dev.eclipse.org/git/org.eclipse.jface/org.eclipse.jface.snippets.git
# Push back to the origin using http
git push origin

 

下面的例子只是用到了Git的配置

// Set proxy for git globally
 git config --global http.proxy http://proxy:8080
// To check the proxy settings
git config --get http.proxy
// Just in case you need to you can also revoke the proxy settings
git config --global --unset http.proxy


1.14 Git服务提供商

除了假设本身的服务,你也可使用Git服务提供商提供的服务。最流行的Git服务提供网站是GitHub和Bitbucket。它们都提供了有限制的免费服务


1.14.1 GitHub

能够经过 https://github.com/ 访问GitHub. GitHub上全部的公开仓库都是免费的。若是你想在上面使用私有的仓库,那么就须要付费给GitHub

 

GitHub须要你建立ssh的公钥私钥。生成一份Ubuntu的公钥私钥能够访问 sshkey creation in Ubuntu ,Windows环境能够访问msysgit ssh key generation.

 

在GitHub上建立一个帐户和一个仓库之后。你会收到如何将你的项目上传到GitHUb的指南,其中的命令大体以下:

 

Global setup:
 Set up git
  git config --global user.name "Your Name"
  git config --global user.email your.email@gmail.com
      
Next steps:
  mkdir gitbook 
  cd gitbook
  git init
  touch README
  git add README
  git commit -m 'first commit'
  git remote add origin git@github.com:vogella/gitbook.git
  git push -u origin master
      
Existing Git Repo?
  cd existing_git_repo
  git remote add origin git@github.com:vogella/gitbook.git
  git push -u origin master


1.14.2 Bitbucket

 

能够经过 https://bitbucket.org/ 访问Bitbucket. Bitbucket 提供了无限制了公共仓库和只能有五我的访问的私有仓库。若是你须要超过五我的访问私有仓库,就须要付费给Bitbucket


1.15 Git的图形接口

 

这个教程主要说明Git命令行的使用。完成了这个教程之后,你可能想要找到一个Git的图形工具

 

Git提供了两个图形工具。 gitk可以展现仓库的历史信息、git gui 让你能够经过编辑器来完成Git操做

 

Eclipse EGit 项目提供了Git与Eclipse的集成,在最新的Eclipse版本中能够找到

 

1.16 Kindle版本教程

 

这个教程提供了Kindle版本

Kindle Edition


1.17 问题与讨论

 

在提出问题以前,请先查看 vogella FAQ. 若是你有任何的问题或者是从文章中找到错误,那么可使用www.vogella.com Google Group. 我本身写了一个简短的列表 how to create good questions 可能会对你有用.