Attention can view more fans exclusive blog~

Cause to think

Recently, I entered a new company and am in the familiar stage, so I haven’t written a blog for some time. In fact, every time you enter a new environment, there will be a lot of development tools and development methods that are different from the way you used before. There is no right or wrong, only appropriate. I recently encountered a Git branch management issue. The trunk branches are the same, consisting of four development, test, pre-release, and release branches, since both use multi-person collaboration to develop mature agile processes. The difference is that for the master branch commit record, one is merge (merge), the other is rebase (rebase), actually the final code is the same. However, this point made me very interested in rebase or merge, and I read Master Git specifically for this purpose.

What is a merge?

Basic operations, a brief introduction to merge.The diagram is the most basic case we encountered during development. We made the Experiment branch based on the master checkout of the C2 node. If we commit C3 to the master branch, the master branch will experiment ahead and commit to the master branch. Then we develop C4 on experiment, and we want to commit C4 to the master branch. We can use merge.

// Current status$ git l
* 19661bd (HEAD -> experiment) C4 - Davids, 4 seconds ago
| * fa0f0a2 (master) C3 - Davids, 21 seconds ago
|/  
* acdf94c C2 - Davids, 2 minutes ago
* 2b55d4e C1 - Davids, 2 minutes ago
Copy the code
// Switch to the master branch and merge the experiment code$ git checkout master
$ git merge experiment
Copy the code

After you run the merge command, a new COMMIT is generated. The viM page is displayed automatically. The default description is as follows

Merge branch 'experiment'
  
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
Copy the code
// After merge, a new MERGE branch 'experiment' COMMIT is generated, which we named C5$ git l
*   177d4c3 (HEAD -> master) Merge branch 'experiment' - Davids, 4 minutes ago
|\  
| * 19661bd (experiment) C4 - Davids, 9 minutes ago
* | fa0f0a2 C3 - Davids, 9 minutes ago
|/  
* acdf94c C2 - Davids, 10 minutes ago
* 2b55d4e C1 - Davids, 10 minutes ago

$ git log --oneline
177d4c3 (HEAD -> master) Merge branch 'experiment'
19661bd (experiment) C4
fa0f0a2 C3
acdf94c C2
2b55d4e C1
Copy the code

What is rebase?

Is it rebase when you use it too much? I’m going to merge. Here’s a quick introduction to what rebase is. The current status is the same as that before merge. (For a more consistent reading, pull down the above image so you don’t have to turn over all the pages.)

You can extract the patches and changes introduced in C4 and then apply them again on top of C3. In Git, this operation is called rebasing. You can use the rebase command to move all changes committed to one branch to another, as if to “replay.”

// Current status$ git l
* e458f64 (HEAD -> experiment) C4 - Davids, 4 seconds ago
| * 77115ac (master) C3 - Davids, 21 seconds ago
|/  
* 360ea4b C2 - Davids, 2 minutes ago
* bfc4923 C1 - Davids, 2 minutes ago
Copy the code
// Start rebase // first go to the base branch and update the code. The purpose is to ensure that the local base branch master has the code we want. If we don't want the latest, or just want the current local master branch, we don't need to do this$ git checkout master

$ git pull origin master// Cut back to the current branch$ git checkout experiment/ / rebase$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: C4

$ git status
On branch experiment
nothing to commit, working tree clean

$ git log --oneline8fe28d4 (HEAD -> Experiment, master) C4 77115AC C3 360ea4b C2 bfc4923 C1$ git l
* 8fe28d4 (HEAD -> experiment, master) C4 - Davids, 17 minutes ago
* 77115ac C3 - Davids, 17 minutes ago
* 360ea4b C2 - Davids, 19 minutes ago
* bfc4923 C1 - Davids, 19 minutes ago
Copy the code

Its principle is to first find C2, the most recent common ancestor of the two branches (i.e., the current branch experiment and the target base branch Master of base-changing operation), and then compare the previous submissions of the current branch with the ancestor to extract the corresponding modifications and save them as temporary files. The current branch is then directed to the target base C3, and the changes previously saved as temporary files are applied sequentially.

$ git checkout master
Switched to branch 'master'

$ git merge experimentUpdating 77115ac.. 8fe28d4 Fast-forward test1.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 test1.txt
$ git status
On branch master
nothing to commit, working tree clean

$ git log --oneline
8fe28d4 (HEAD -> master, experiment) C4
77115ac C3
360ea4b C2
bfc4923 C1

$ git l
* 8fe28d4 (HEAD -> master, experiment) C4 - Davids, 19 minutes ago
* 77115ac C3 - Davids, 19 minutes ago
* 360ea4b C2 - Davids, 21 minutes ago
* bfc4923 C1 - Davids, 21 minutes ago
Copy the code

At this point, the snapshot pointed to by C4′ is exactly the same as the snapshot pointed to by C5 in the merge example above. There is no difference in the end result between the two consolidation methods, but the rebasing makes the commit history cleaner. When you look at the history of a branch that has been refocused, you see that although the actual development work is in parallel, it appears to be sequential, with the commit history being a straight line without forks.

Typically we do this to ensure that we keep our commit history clean when pushing to remote branches — for example, when contributing code to a project maintained by someone else. In this case, you develop in your own branch first, and when the development is complete you need to base your code on Origin/Master first, and then commit the changes to the main project. This way, the maintainers of the project no longer need to do the integration work, but just fast-forward the merge.

Note that whether through rebasing or a three-way merge, the end result of consolidation always points to the same snapshot, just with a different commit history. Rebasing is applying a series of commits in their original order to another branch, while merging is combining the final result.

conclusion

So far, you’ve had a brief introduction to merge versus Rebase, and which is better. Before we answer that question, let’s take a step back and discuss what submitting history really means.

There is a view that the commit history of the warehouse is a record of what actually happened. It is a historical document that is valuable in its own right and cannot be tampered with. From this point of view, changing the submission history is sacrilege, and you use _ lies _ to cover up what actually happened. What if the commit history resulting from the merge is a mess? Since that was the case, the traces should be preserved for future generations to look at.

The other side of the argument is that the submission history is the story that happened during the project. No one publishes the first drafts of a book, and software maintenance manuals need to be revised repeatedly to make them easy to use. People with this view use tools like Rebase and filter-Branch to write stories in whatever way is convenient for later readers.

Now, let’s go back to the question, is it better to merge or to rebase? I hope you understand that there is no simple answer. Git is a very powerful tool that allows you to do a lot of things with commit history, but every team and every project has different needs for it. Now that you’ve learned how to use both, you’ll be able to make an informed choice based on the situation.

As a general rule, only base cleanup history on local changes that haven’t been pushed or shared with others, and never base commits that have been pushed elsewhere, so you can get the benefit of both approaches.