As we all know, Git is currently the leader in the field of distributed version control, and a complete ecosystem has been formed around Git. To learn Git, the first step is to learn the basic workflow of Git. Compared with traditional version control systems such as SVN, Git is a powerful tool designed for distributed version control. Commonly used commands when using Git include pull, commit, push, etc., which seem to be very simple. However, sometimes you will encounter merge conflicts. Git will mark the conflicts and require you to resolve them manually. Sometimes, you accidentally commit code to the wrong branch and push it to the remote repository. There are also times when you need to switch to a different branch, but Git won't let you do it because there are still unsaved changes. What if you need to patch the code through a commit from another branch? This article will introduce 12 advanced Git commands. Proper use of these commands can greatly improve the efficiency of applying Git.
1. Use rebase instead of merge to pull upstream modifications
The branch merge will be recorded as a merge commit, which makes sense. For example, this can be used to indicate that a new feature has been merged into a release branch. However, when multiple team members work on a project and use regular git pulls to sync branches, the commit timeline becomes polluted with unnecessary merge commits. A better approach is to use git rebase to rebase a feature branch to the master branch:
$ git checkout feature $ git rebase master
Doing so will move the entire feature branch to the starting point of the master branch, and it will merge all new commits on the master branch. However, compared to using merge commits, rebasing rewrites the project history by creating a new commit for each commit in the original branch. The main benefit of rebasing is that you get a cleaner project history. Additionally, there is some discussion here about the pitfalls of rebasing.
2. Resolve merge conflicts after executing git rebase
Just as with greater ability comes greater responsibility. When performing a git rebase, you may encounter merge conflicts. A merge conflict means that two commits modified the same line of the same file, and Git doesn't know which change to apply. This results in an error message like this:
Git will give you 3 options to fix the commit that caused the conflict (fa39187):
You can run git rebase --abort to completely cancel the rebase. Doing so will cancel the rebase changes and return the branch to the state it was in before executing git rebase.
You can run git rebase --skip to completely ignore the commit. This way, changes introduced by the commit in question are not added to history.
Conflicts can be resolved using the same standard steps as merge conflicts.
3. Temporarily save changes
When work is in progress, some things are often in a messy state. What should I do if I need to switch to a different branch at this time? Git doesn't allow you to do this because there are still unsaved changes. Frankly speaking, you don't want to submit a half-finished product and revise it later. The solution to this problem is to use the git stash command. Stash will receive the current status of the working directory (for example, modified tracking files and modifications to the staging area, etc.) and save it to the unfinished modification stack, so that it can be modified at any time later. You can use the following command to stash your work:
$ git stash
Saved working directory and index state WIP on feature: 3fc175f fix race condition
HEAD is now at 3fc175f fix race condition
Now, the working directory is clean Now:
$ git status # On branch feature nothing to commit, working directory clean
At this time, you can safely switch branches to do other things. But don’t worry, the staged commits are still there:
$ git stash list stash@{0}: WIP on feature: 3fc175f fix race condition
Later, after returning to the feature branch, you can retrieve all staged changes:
$ git stash pop On branch feature Changes not staged for commit: (use "git add ..." to update what will be committed) modified: index.html Dropped refs/stash@{0} (ac2321cc3a33ba712b8e50c99a99d3c20da9d6b8)
There are some other options available when it comes to staging , as shown below:
$ git stash save "describe it" # give the stash a name $ git stash clear # delete a stashed commit $ git stash save --keep-index # stash only unstaged files
4. Clone a specific remote branch
What should you do if you want to clone a specific branch from the remote repository? Normally you would use git clone, but doing so will clone all other branches as well. A convenient way is to use git remote add:
$ git init $ git remote add -t-f origin$ git checkout
5. Merge cherry-pick remote commits into your own branch
What's more, if you only want to merge a specific commit from the remote warehouse into your own branch how should I do it? You can use git cherry-pick to select a commit with a given SHA value and merge it into the current branch:
$ git cherry-pick
6. Apply patches from an unrelated local repository
If you need to merge another unrelated local repository How to apply the submitted patch of the warehouse to the current warehouse? The answer is the following command:
$ git --git-dir=/.git format-patch -k -1 --stdout| git am -3 -k
7. Ignore changes in tracking files
如果你和你的同事操纵的是相同分支,那么很有可能需要频繁执行git merge或是git rebase。不过,这么做可能会重置一些与环境相关的配置文件,这样在每次合并后都需要修改。与之相反,你可以通过如下命令永久性地告诉Git不要管某个本地文件:
$ git update-index --assume-unchanged
8. 每隔X秒运行一次git pull
通常,合并冲突出现的原因在于你正在工作的本地仓库不再反映远程仓库的当前状态。这正是我们为什么每天早晨要首先执行一次git pull的缘故。此外,你还可以在后台通过脚本(或是使用GNU Screen)每隔X秒调用一次git pull:
$ screen $ for((i=1;i<=10000;i+=1)); do sleep X && git pull; done
9. 将子目录分隔为新的仓库
有时,你可能需要将Git仓库中某个特定的目录转换为一个全新的仓库。这可以通过git filter-branch来实现:
$ git filter-branch --prune-empty --subdirectory-filtermaster # Filter the master branch to your directory and remove empty commits Rewrite 48dc599c80e20527ed902928085e7861e6b3cbe6 (89/89) Ref 'refs/heads/master' was rewritten
现在,仓库会包含指定子目录中的所有文件。虽然之前的所有文件都会被删除,但他们依旧存在于Git历史中。现在可以将新的本地仓库推送到远程了。
10. 清理
有时,Git会提示“untracked working tree files”会“overwritten by checkout”。造成这种情况的原因有很多。不过通常来说,我们可以使用如下命令来保持工作树的整洁,从而防止这种情况的发生:
$ git clean -f # remove untracked files $ git clean -fd # remove untracked files/directories $ git clean -nfd # list all files/directories that would be removed
11. 将项目文件打成tar包,并且排除.git目录
有时,你需要将项目副本提供给无法访问GitHub仓库的外部成员。最简单的方式就是使用tar或zip来打包所有的项目文件。不过,如果不小心,隐藏的.git目录就会包含到tar文件中,这会导致文件体积变大;同时,如果里面的文件与接收者自己的Git仓库弄混了,那就更加令人头疼了。轻松的做法则是自动从tar文件中排除掉.git目录:
$ tar cJf.tar.xz/ --exclude-vcs
12. 查找修改者
最后,如果出现混乱的情况,你一定想要找出是谁造成的。如果生产服务器宕机,那么找到罪魁祸首是比较容易的事情:只需执行git blame。该命令会显示出文件中每一行的作者,提交hash则会找出该行的上一次修改,还能看到提交的时间戳:
$ git blame
当然,Git命令是非常多的,除了上面介绍的12个重要命令外,相信各位InfoQ读者在日常工作过程中也有自己偏爱且好用的一些命令,不妨以评论的形式与其他读者一同分享。