如果在你的工作副本中,你创建了不想被提交的文件,你可以丢弃它。
# 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
Git可以使用对历史记录中的任一版本进行标记。这样在后续的版本中就能轻松的找到。一般来说,被用来标记某个发行的版本
可以通过git tag命令列出所有的标记,通过如下命令来创建一个标记和恢复到一个标记
git tag version1.6 -m 'version 1.6' git checkout <tag_name>
通过分支,可以创造独立的代码副本。默认的分支叫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
通过Merge我们可以合并两个不同分支的结果。Merge通过所谓的三路合并来完成。分别来自两个分支的最新commit和两个分支的最新公共commit
可以通过如下的命令进行合并
# Syntax: git merge <branch-name>
git merge testing
一旦合并发生了冲突,Git会标志出来,开发人员需要手工的去解决这些冲突。解决冲突以后,就可以将文件添加到索引中,然后提交更改
删除分支的命令如下:
#Delete branch testing git branch -d testing # Check if branch has been deleted git branch
默认的,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更改。另外的,你可以使用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"
通过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信息(待理解)
你也可以对两个分支进行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
在push更改到其他的Git仓库之前,我们需要仔细检查本地分支的commit历史
在Git中,你可以使用本地的commit。开发人员可以利用这个功能方便的回滚本地的开发历史。但是在push之前,需要观察你的本地分支历史,是否其中有些commit历史对其他用户来说是无关的
如果所有的commit历史都跟同一个功能有关,很多情况下,你需要rebase这些commit历史为一个commit历史。
交互性的rebase主要就是做重写commit历史的任务。这样做是安全的,因为commit还没有被push到其它的仓库。这意味着commit历史只有在被push之前被修改
如果你修改然后push了一个已经在目标仓库中存在的commit历史,这看起来就像是你实现了一些别人已经实现的功能
一个补丁指的是一个包含对源代码进行修改的文本文件。你可以将这个文件发送给某人,然后他就可以应用这个补丁到他的本地仓库
下面会创建一个分支,对这个分支所一些修改,然后创建一个补丁,并应用这个补丁到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
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中还没有支持。同名命令不能以!开始。
有时候,你不希望某些文件或者文件夹被包含在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
命令
下面列出了在日常工作中非常有用的Git命令
命令 | 描述 |
---|---|
git blame filename |
谁创建了或者是修改了这个文件 |
git checkout -b mybranch master~1 |
以上上个commit信息为起点,创建一条新的分支 |
如上所述,我们的操作不需要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
Git支持远端的操作。Git支持多种的传输类型,Git自带的协议就叫做git。下面的的命令通过git协议从克隆一个仓库
git clone [email protected]:vogella/gitbook.git
同样的,你可以通过http协议来克隆仓库
# The following will clone via 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
如果你的防火墙屏蔽了出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
除了假设自己的服务,你也可以使用Git服务提供商提供的服务。最流行的Git服务提供网站是GitHub和Bitbucket。它们都提供了有限制的免费服务
可以通过 https://github.com/ 访问GitHub. GitHub上所有的公开仓库都是免费的。如果你想在上面使用私有的仓库,那么就需要付费给GitHub
GitHub需要你创建ssh的公钥私钥。生成一份Ubuntu的公钥私钥可以访问 ssh key 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 [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 origin [email protected]:vogella/gitbook.git git push -u origin master