5. 远端仓库(remote repositories)
5.1. 设置一个远端的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
5.2. 推送更改到其他的仓库
做一些更改,然后将这些更改从你的第一个仓库推送到一个远端仓库
- # 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
5.3. 添加远端仓库
除了通过完整的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
5.4. 显示已有的远端仓库
通过以下命令查看已经存在的远端仓库
- # Show the existing defined remote repositories
- git remote
5.5. 克隆仓库
通过以下命令在新的目录下创建一个新的仓库
- # Switch to home
- cd ~
- # Make new directory
- mkdir repo02
- # Switch to new directory
- cd ~/repo02
- # Clone
- git clone ../remote-repository.git .
5.6. 拉取(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
6. 还原更改
如果在你的工作副本中,你创建了不想被提交的文件,你可以丢弃它。
- # 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
如果你还未把更改加入到索引中,你也可以直接还原所有的更改
- #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/visual-git-guide/index-en.html
7. 标记
Git可以使用对历史记录中的任一版本进行标记。这样在后续的版本中就能轻松的找到。一般来说,被用来标记某个发行的版本
可以通过git tag命令列出所有的标记,通过如下命令来创建一个标记和恢复到一个标记
- git tag version1.6 -m 'version 1.6'
- git checkout
8. 分支、合并
8.1. 分支
通过分支,可以创造独立的代码副本。默认的分支叫master。Git消耗很少的资源就能创建分支。Git鼓励开发人员多使用分支
下面的命令列出了所有的本地分支,当前所在的分支前带有*号
如果你还想看到远端仓库的分支,可以使用下面的命令
可以通过下面的命令来创建一个新的分支
- #Syntax: git branch
- # 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
8.2. 合并
通过Merge我们可以合并两个不同分支的结果。Merge通过所谓的三路合并来完成。分别来自两个分支的最新commit和两个分支的最新公共commit
可以通过如下的命令进行合并
- # Syntax: git merge
- git merge testing
一旦合并发生了冲突,Git会标志出来,开发人员需要手工的去解决这些冲突。解决冲突以后,就可以将文件添加到索引中,然后提交更改
8.3. 删除分支
删除分支的命令如下:
- #Delete branch testing
- git branch -d testing
- # Check if branch has been deleted
- git branch
8.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
通过这种方式,你可以确定哪些分支对于其他仓库是可见的,而哪些只是本地的分支
9. 解决合并冲突
如果两个不同的开发人员对同一个文件进行了修改,那么合并冲突就会发生。而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将冲突放在收到影响的文件中,文件内容如下:
- > 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"
10. 变基(Rebase)
10.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。你可以通过如下的命令交互的完成
这个命令会打开编辑器让你修改commit的信息或者 squash/ fixup最后一个信息。
Squash会合并commit信息而fixup会忽略commit信息(待理解)
10.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
10.3.Rebase最佳实践
在push更改到其他的Git仓库之前,我们需要仔细检查本地分支的commit历史
在Git中,你可以使用本地的commit。开发人员可以利用这个功能方便的回滚本地的开发历史。但是在push之前,需要观察你的本地分支历史,是否其中有些commit历史对其他用户来说是无关的
如果所有的commit历史都跟同一个功能有关,很多情况下,你需要rebase这些commit历史为一个commit历史。
交互性的rebase主要就是做重写commit历史的任务。这样做是安全的,因为commit还没有被push到其它的仓库。这意味着commit历史只有在被push之前被修改
如果你修改然后push了一个已经在目标仓库中存在的commit历史,这看起来就像是你实现了一些别人已经实现的功能
|