I started to use Git for code management from the beginning of programming. First I played Github by myself, and then used Gitlab at work. Although it took a long time, I only performed some common operations, such as pushing and pulling code, submitting, merging, etc., more complex operations I haven't used it, and I gradually forgot the tutorials I have read. I am a little sorry to Linus.
I always have to pay back when I come out. I encountered a very bad scene in Git a few days ago, and paid the price of an afternoon for not having a deep understanding of Git commands.
Let me introduce this scenario first. When one of our projects was upgraded from version N to version A, we introduced the jar package of another project, and successively released versions B and C, but suddenly found the jar package introduced by version A after version C There are huge performance problems. Versions B and C are released based on version A. To fix the performance problems of the jar package, it will take a few days to wait for the jar package to be released again, but at this time there are urgent bugs to be fixed online. So I fell into a dilemma.
In the end, I decided to roll back the code to version A before fixing the bug based on the old version, and started a five-hour road of suffering.
basic exploration
revert
The first thing to be sure is revert, git revert commit_id can generate a commit that is exactly the opposite of commit_id, that is, commit_id is to add, and revert is to delete.
But after using git log to check the submission records, I dispelled this idea, because there were too many submissions, and there were several merge operations from other branches in the middle. "Benefit from" our unclean submission records. To complete the revert from version C to version N, I need to perform the revert operation in reverse order dozens of times. If the order is wrong once, the final result may be wrong.
In addition, we know that when we merge the code, we will also generate a new submission of the merge information. When revert this merge commit, we need to specify the m parameter to specify the mainline. This mainline is the main line and the main branch where we want to keep the code. , Merge from the feature branch to the develop branch, or the commit from the develop branch to the master is OK, but when the feature branches are merged with each other, how can I know which one is the main line?
So the revert copy was abandoned.
Reset
Then consider reset. Reset can also make the code go back to a certain commit, but unlike revert, reset refers to the HEAD pointer of the commit to a certain commit, and subsequent commit records will disappear, just like never before. Submit once.
But since we are all developing on the feature branch, I rolled back the code on the feature branch to a certain commit and then merged it into the develop branch, but I was prompted to report an error. This is because after the feature branch is reverted and submitted, in the git workflow, the feature branch lags behind the develop branch, and merging to the develop branch requires the latest synchronization with the develop branch, and the data of the develop branch needs to be merged into After the feature branch is merged, the code that was reset is back.
At this time, another option is to perform reset on the master branch, use the --hard option to completely discard the old code, and then force it to the remote after reset.
master> git reset --hard commit_id
master> git push --force origin master
But there are still problems. First of all, our master branch is protected in gitlab, and force push cannot be used. After all, the risk is quite high. In case someone resets to the initial submission and then forces push, although it can be restored using reflog, But it was also a lot of toss.
In addition, reset is too barbaric after all, we still want to keep the submission history, and you can refer to it for troubleshooting in the future.
upgrade fusion
rebase
I had to use the search engine to continue searching, and saw someone suggested that you can use rebase to merge multiple submissions into one submission, and then use revert to generate a reverse submission. The idea of this method is very clear. The two commands revert and rebase are combined very well. Well, it is equivalent to the upgraded version of using revert.
Let me talk about rebase first. Rebase means "rebase". The "base" here refers to the git workflow formed by [multiple] commits. Using rebase, we can change these historical submissions, modify the commit information, and change Multiple commits are combined.
There are many documents that introduce rebase, let's directly use it to perform code rollback steps.
- First, cut out a new branch F, and use git log to query the commit version N to be rolled back to.
- After using the command git rebase -i N, -i to specify the interactive mode, the git rebase editing interface will be opened, which looks like:
pick 6fa5869 commit1
pick 0b84ee7 commit2
pick 986c6c8 commit3
pick 91a0dcc commit4
- These commits are arranged from old to new from top to bottom, we only need to add operation commands before commit_id. In the requirement of merging commit, we can choose pick(p) the oldest commit1, and then add it before the subsequent commit_id The squash(s) command merges these commits into the oldest commit1.
- After saving the rebase results, edit the commit information to make this rebase invalid. Git will delete all the previous commits and merge them into a new commit5. If something goes wrong, you can also use git rebase --abort/ --continue/--edit-todo undo and continue editing the previous edit.
- At this time, the commit records on the main branch are older, commit1, commit2, commit3, commit4, and the commit records on the F branch are older, commit5. Since the ancestor node of the F branch is older, it is obviously behind the commit4 of the main branch. It is not allowed to merge the F branch to the main branch, so we need to execute git merge master to merge the main branch to the F branch. After the merge, git will find that the content of commit1 to commit4 is exactly the same as the modification content of commit5 on the F branch. Will be merged automatically, the content remains the same, but there is one more commit5.
- Then, perform a revert anti-commit on commit5 on the F branch, and then all the commits from commit1 to commit4 will be rolled back.
The trick of this method is that it cleverly uses the function of rebase operation history submission and the feature of git to recognize and modify the same automatic merging. Although the operation is complicated, the history submission remains fairly intact.
The rebase modification history submission function is very practical. It can solve the problem that we encountered a small feature that we have submitted many times and messed up the git history. Just pay attention to avoiding multiple people developing at the same time. Just use the branch.
Unfortunately, I did not understand the idea of rebase that day, and because I tried several methods, I couldn’t get too panic. After the rebase was completed, the merge to the main branch was rejected, and I doubted the feasibility of these methods. , Coupled with a colleague’s suggestion that sounds more feasible, interrupted the operation.
File operations
- This more feasible way is to operate on the file, and then let git recognize the change, specifically:
- Cut out a branch F that is identical to the main branch from the main branch.
- Copy the project folder from the file management system to bak, and use git checkout N in bak to cut the code to the desired historical submission. At this time, git will restore the files in bak to the N state.
- In the slave file management system, copy and paste all the contents of the bak folder except the .git folder to the original project directory. git will recognize the changes purely from the file level, and then update the workspace.
- Execute add and commit in the original project directory to complete the anti-commit.
- The ingenuity of this approach is that it uses git itself to recognize files and does not involve workflow operations.
Summary
Finally, relying on the file operation method to successfully complete the code rollback, it was really sad to think about it afterwards.
In order to make my five hours not in vain, I will review the scene at that time, learn and summarize the four ways of code fallback:
- Revert is suitable for scenarios where there are not many historical submissions that need to be rolled back and there are no merge conflicts.
- If you can force the code to the master, and you want to prevent traces of the rolled back code from appearing in the git log, you can use git reset --hard + git push --force.
- If you are a bit geek, pursue a "regular and orthodox" way to revert the code, rebase + revert meets your needs.
- If you don't care about elegance and want to use the simplest and most direct way, file operations are just right.
Git is really a very awesome code management tool. It's easy to get started. The combination of three or five commands is enough to complete the work requirements. It is also very friendly to geekers. It supports all the operations you want, and there is no end to learning.
Source: Zhan Xiaolang's blog
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。