Git
概述
Git是用C语言开发的分布版本控制系统。分布版本控制系统不需要一个集中式的代码仓库。
术语
- 仓库 (Repository)
一个仓库包括了所有的版本信息、所有的分支和标记信息。在Git中仓库的每份拷贝都是完整的。仓库让你可以从中取得你的工作副本。 - 分支 (Branches)
一个分支意味着一个独立的、拥有自己历史信息的代码线 code line 你可以从已有的代码中生成一个新的分支,这个分支与剩余的分支完全独立,默认的分支往往是叫master。用户可以选择一个分支,选择一个分支叫做checkout. - 标记 (Tags)
一个标记指的是某个分支某个特定时间点的状态。通过标记,可以很方便的切换到标记时的状态。例如2009年1月25号在testing分支上的代码状态。 - 提交 (Commit)
提交代码后,仓库会创建一个新的版本。这个版本可以在后续被重新获得。每次提交都包括作者和提交者,作者和提交者可以是不同的人。 - URL
URL用来标识一个仓库的位置 - 修订 (Revision)
用来表示代码的一个版本状态。Git通过用SHA1 hash算法表示的id来标识不同的版本,每一个 SHA1 id都是160位长、16进制标识的字符串.。最新的版本可以通过HEAD来获取,之前的版本可以通过"HEAD~1"来获取,以此类推 。
索引
Git需要将代码的变化显示的与下一次提交进行关联。举个例子,如果你对一个文件进行了修改,然后想将这些修改提交到下一次提交中 ,你必须将这个文件提交到索引中。通过git add file命令,这样索引可以保存所有变化的快照,新增的文件总是要显示的添加到索引中来,对于那些之前已经提交过的文件,可以在commit命令中使用a 选项达到提交到索引的目的。
安装
Mac上:
brew install git
配置
可以在.gitconfig文件中放置git的全局配置,文件位于用户的home目录。
-
用户信息
# Configure the user which will be used by git # Of course you should use your name git config global user.name "Example Surname" # Same for the email address git config global user.email "[email protected]" # Set default so that all changes are always pushed to the repository git config global push.default "matching"
-
高亮显示
git config global color.status auto git config global color.branch auto
忽略特定的文件
可以配置Git忽略特定的文件或者是文件夹。这些配置都在.gitignore文件中,这个文件可以存在于不同的文件夹中,可以包含不同的文件匹配模式。同时Git也提供了全局的配置 core.excludesfile 。
Git基础操作
后续将通过一个典型的Git工作流来学习。在这个过程中,你会创建一些文件,创建一个本地的Git仓库,提交你的文件到这个仓库中。这之后,你会克隆一个仓库,在仓库之间通过pull和push操作来交换代码的修改。注释(以#开头)解释了命令的具体含义。
让我们打开命令行开始操作吧!!!
-
创建内容
# Switch to home cd ~ # Create a directory mkdir ~/repo01 # Switch to ~/repo01 cd repo01 # Create a new directory mkdir datafiles # Create a few files touch test01 touch test02 touch test03 touch datafiles/data.txt # Put a little text into the first file ls > test 01
-
创建仓库、添加文件索引
# Initialize the local Git repository git init # Add all (files and directories) to the Git repository git add . # Make a commit of your file to the local repository git commit -m "Initial commit" # Show the log file git log
-
diff命令与commit更改
通过git diff命令 用户可以查看更改 通过改变一个文件的内容 看看git diff命令输出什么 然后提交这个更改到仓库中# Make some changes to the file echo "This is a change" > test01 echo "and this is another change" > test02 # Check the changes via the diff command git diff # Commit the changes, -a will commit changes for modified files # but will not add automatically new files git commit -a -m "These are new changes"
-
Status,Diff和Commit Log
下面会展示仓库现有的状态以及过往的提交历史# Make some changes in the file echo "This is a new change" > test01 echo "and this is another new change" > test02 # See the current status of your repository # (which files are changed / new / deleted) git status # Show the differences between the uncommitted files # and the last commit in the current branch git diff # Add the changes to the index and commit git add . && git commit -m "More changes typo in the commit message" # Show the history of commits in the current branch git log # This starts a nice graphical view of the changes gitk --all
更改提交的信息git amend
git commit --amend -m "More changes now correct"-
删除文件
如果删除了一个在版本控制之下的文件,那么使用git add .不会在索引中删除这个文件。需要通过带a选项的git commit命令和A选项的git add命令来完成# Create a file and put it under version control touch nonsense.txt git add . && git commit -m "a new file has been created" # Remove the file rm nonsense.txt # Try standard way of committing -> will not work git add . && git commit -m "a new file has been created" # Now commit with the a flag git commit -a -m "File nonsense.txt is now removed" # Alternatively you could add deleted files to the staging index via git add -A . git commit -m "File nonsense.txt is now removed"
远端仓库(remote repositories)
-
设置一个远端的Git仓库
我们将创建一个远端的Git仓库,这个仓库可以存储在本地或者是网络上。
远端Git仓库和标准的Git仓库有如下差别:一个标准的Git仓库包括了源代码和历史信息记录,我们可以直接在这个基础上修改代码。因为它已经包含了一个工作副本。但是远端仓库没有包括工作副本,只包括了历史信息,可以使用bare选项来创建一个这样的仓库。#Switch to the first repository cd ~/repo01 git clone --bare . ../remote-repository.git # Check the content, it is identical to the .git directory in repo01 ls ~/remote-repository.git
推送更改到其他仓库
# Make some changes in the first repository
cd ~/repo01
# Make some changes in the file
echo "Hello, hello. Turn your radio on" > test01
echo "Bye, bye. Turn your radio off" > test02
# Commit the changes, -a will commit changes for modified files
# but will not add automatically new files
git commit -a -m "Some changes"
# Push the changes
git push ../remote-repository.git添加远端仓库
除了通过完整的URL来访问Git仓库外,还可以通过git remote add命令为仓库添加一个短名称。当你克隆了一个仓库以后,origin表示所克隆的原始仓库,即使我们从零开始,这个名称也存在。
# Add ../remote-repository.git with the name origin
git remote add origin ../remote-repository.git
# Again some changes
echo "I added a remote repo" > test02
# Commit
git commit -a -m "This is a test for the new remote origin"
# If you do not label a repository it will push to origin
git push origin显示已有的远端仓库
# Show the existing defined remote repositories
git remote克隆仓库
# Switch to home
cd ~
# Make new directory
mkdir repo02
# Switch to new directory
cd ~/repo02
# Clone
git clone ../remote-repository.git .拉取(Pull)更改
通过拉取,可以从其他的仓库中获取最新的更改。在第二个仓库中 ,做一些更改,然后将更改推送到远端的仓库中,然后第一个仓库拉取这些更改。
# Switch to home
cd ~
# Switch to second directory
cd ~/repo02
# Make changes
echo "A change" > test01
# Commit
git commit -a -m "A change"
# Push changes to remote repository
# Origin is automatically maintained as we cloned from this repository
git push origin
# Switch to the first repository and pull in the changes
cd ~/repo01
git pull ../remote-repository.git/
# Check the changes
less test01
还原更改
如果在你的工作副本中,你创建了不想被提交的文件,你可以丢弃它。
# 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 后加commitid就是把commit的内容复制到index和工作副本中)
git checkout commit_name
如果你还未把更改加入到索引中 你也可以直接还原所有的更改
# Some nonsense change
echo "nonsense change" > test01
# Not added to the staging index. Therefore we can
# just checkout the old version
# checkout后如果没有commit id号,就是从index中拷贝数据到工作副本,不涉及commit部分的改变
git checkout test01
# Check the result
cat test01
# Another nonsense change
echo "another nonsense change" > test01
# We add the file to the staging index
git add test01
# Restore the file in the staging index
# 复制HEAD所指commit的test01文件到index中
git reset HEAD test01
# Get the old version from the staging index
# 复制index中test01到工作副本中
git checkout test01
# 以上两条命令可以合并为git checkout HEAD test01
也可以通过revert命令进行还原操作。
# Revert a commit
git revert commit_name
即使你删除了一个未添加到索引和提交的文件 你也可以还原出这个文件。
# Delete a file
rm test01
# Revert the deletion
git checkout test01
如果你已经添加一个文件到索引中,但是未提交,可以通过git reset file命令将这个文件从索引中删除。
# 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/visualgitguide/index-en.html]
标记
Git可以使用对历史记录中的任一版本进行标记,这样在后续的版本中就能轻松的找到。一般来说,被用来标记某个发行的版本。
可以通过git tag命令列出所有的标记。通过如下命令来创建一个标记和恢复到一个标记:
git tag version1.6 -m 'version 1.6'
git checkout
分支、合并
分支
通过分支可以创造独立的代码副本。默认的分支叫master。Git消耗很少的资源就能创建分支。Git鼓励开发人员多使用分支。
列出所有的本地分支:
git branch
如果还想看到远端分支":
git branch -a
创建一个新的分支:
# 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
合并
通过Merge我们可以合并两个不同分支的结果M。erge通过所谓的三路合并来完成。分别来自两个分支的最新commit和两个分支的最新公共commit.
git merge testing
一旦合并发生了冲突,Git会标志出来,开发人员需要手工的去解决这些冲突。解决冲突以后,就可以将文件添加到索引中,然后提交更改。
删除分支
# Delete branch testing
git branch -d testing
# Check if branch has been deleted
git branches
推送一个分支到远端仓库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
解决并合并冲突
如果两个不同的开发人员对同一个文件进行了修改,那么合并冲突就会发生。而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更改。另外的,你可以使用gitmergetool命令:
Either edit the file manually or use
git merge tool
# 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"
在线的远端仓库
克隆远端仓库
Git支持远端的操作,Git支持多种的传输类型,Git自带的协议就叫做git,下面的的命令通过git协议从克隆一个仓库:
git clone [email protected]:vogella/gitbook.git
同样的 你可以通过http协议来克隆仓库
git clone http://[email protected]/vogella/gitbook.git
添加远端仓库
如果你克隆了一个远端仓库,那么原先的仓库就叫做origin.
你可以push修改到origin中,通过 git push origin 命令. 当然 push到一个远端的仓库需要对仓库的写权限
你可以通过git remote add name gitrepo命令添加多个仓库.例如 你可以通过http协议再次添加之前clone过来的仓库:
# Add the https protocol
git remote add githttp https://[email protected]/vogella/gitbook.git
Github指南
在GitHub上创建一个账户和一个仓库以后,你会收到如何将你的项目上传到GitHUb的指南。其中的命令大致如下:
Global setup:
Set up git
git config global user.name "Your Name"
git config global user.email [email protected]
Next steps:
mkdir gitbook
cd gitbook
git init
touch README
git add README
git commit m 'first commit'
git remote add origin [email protected]:vogella/gitbook.git
git push u origin master
Existing Git Repo?
cd existing_git_repo
git remote add [email protected]:vogella/gitbook.git
git push u origin master