So sánh rebasse và merge git
Mỗi khi làm xong một tính năng, chúng ta tiến hành merge nó vào develop. Lệnh Show
Gần đây, bạn nghe đến lệnh Nhưng hẳn bạn đã nghe lời khuyên rằng: nếu là người mới thì đừng vội sử dụng Một trường hợp phổ biếnTrong thực tế, nhiều dự án có hai nhánh cơ bản là master và develop. Mã trong master được go production còn mã trong develop thì được chạy trong môi trường development. (Thực tế các nhánh có thể nhiều hơn và phức tạp hơn nhưng tôi chỉ lấy ví dụ cơ bản). Để phát triển một tính năng mới, tôi checkout từ develop ra một nhánh mới rồi phát triển trên đó. Các nhánh có thể theo quy tắc feature/01, feature/02… với 01, 02… là tên của tính năng. Trong quá trình phát triển, có thể có nhiều tính năng được phát triển cùng lúc và độc lập với nhau. Đến một lúc nào đó bạn cần những thay đổi từ feature/01 vào feature/02 thì sao? Merge feature/01 vào feature/02? Không tồi! Nhưng nếu tiếp tục làm thế lịch sử commit của bạn có thể sẽ rối tung lên, thay vào đó sao không thử cách này? Nguyên tắc: Luôn để develop làm nhánh trung gian giữa các nhánh tính năng, bởi tính năng suy cho cùng sẽ phải đưa vào develop. Nên nếu cần các thay đổi từ feature/01 vào feature/02 bạn hãy merge feature/01 vào develop, và từ feature/02 tiến hành rebase develop. Nếu từ feature/02 mà merge trực tiếp feature/01 thì sẽ có lịch sử commit trông như thế này: Trông cây git phần phức tạp hơn so với cách ban đầu rồi đúng không? Nguyên tắc vàng của rebaseQuy tắc vàng của rebase được nêu ra rất rõ trong bài viết . Tôi sẽ tóm tắt lại, là không bao giờ sử dụng rebase trên nhánh dùng chung. Trong ví dụ trên nhánh dùng chung là develop. Vì sao? Nếu từ develop mà ta tiến hành rebase feature/01 hoặc feature/02 thì lúc này lịch sử commit trên develop "bị viết lại". Như trên, khi từ develop (trong hình là Main) mà rebase feature/01, các commit mới của develop được thêm vào sau commit mới nhất của feature. Lúc này nhánh develop, lịch sử commit "bị viết lại". Tưởng tượng mà xem khi có nhiều người đang làm việc dựa trên nhánh develop từ thời điểm trước đó. Sau này có thực hiện thao tác merge sẽ gây ra nhiều vấn đề khó hiểu. Tổng kếtTóm lại, merge luôn đủ dùng. Bạn không cần biết đến rebase cũng chẳng sao. Nhưng nếu muốn có một cây lịch sử git trông gọn gàng hơn thì hãy thử rebase. Quy tắc vàng là không bao giờ rebase feature vào develop (không bao giờ rebase trên nhánh dùng chung). Chỉ từ feature rebase develop, và ngược lại, từ develop merge feature. The easiest option is to merge the
Or, you can condense this to a one-liner: This creates a new “merge commit” in the
0 branch that ties together the histories of both branches, giving you a branch structure that looks like this:
Merging is nice because it’s a non-destructive operation. The existing branches are not changed in any way. This avoids all of the potential pitfalls of rebasing (discussed below). On the other hand, this also means that the
0 branch will have an extraneous merge commit every time you need to incorporate upstream changes. If
3 options, it can make it hard for other developers to understand the history of the project. The rebase optionAs an alternative to merging, you can rebase the
0 branch onto
This moves the entire
0 branch to begin on the tip of the
The major benefit of rebasing is that you get a much cleaner project history. First, it eliminates the unnecessary merge commits required by
9. Second, as you can see in the above diagram, rebasing also results in a perfectly linear project history—you can follow the tip of
0 all the way to the beginning of the project without any forks. This makes it easier to navigate your project with commands like
3,
2, and
3. But, there are two trade-offs for this pristine commit history: safety and traceability. If you don’t follow the , re-writing project history can be potentially catastrophic for your collaboration workflow. And, less importantly, rebasing loses the context provided by a merge commit—you can’t see when upstream changes were incorporated into the feature. Interactive rebasingInteractive rebasing gives you the opportunity to alter commits as they are moved to the new branch. This is even more powerful than an automated rebase, since it offers complete control over the branch’s commit history. Typically, this is used to clean up a messy history before merging a feature branch into To begin an interactive rebasing session, pass the
5 option to the
6 command:
This will open a text editor listing all of the commits that are about to be moved:
This listing defines exactly what the branch will look like after the rebase is performed. By changing the
7 command and/or re-ordering the entries, you can make the branch’s history look like whatever you want. For example, if the 2nd commit fixes a small problem in the 1st commit, you can condense them into a single commit with the
8 command:
When you save and close the file, Git will perform the rebase according to your instructions, resulting in project history that looks like the following:
Eliminating insignificant commits like this makes your feature’s history much easier to understand. This is something that
9 simply cannot do. The golden rule of rebasingOnce you understand what rebasing is, the most important thing to learn is when not to do it. The golden rule of
6 is to never use it on public branches. For example, think about what would happen if you rebased
0 branch:
The rebase moves all of the commits in
0. The problem is that this only happened in your repository. All of the other developers are still working with the original The only way to synchronize the two So, before you run
6, always ask yourself, “Is anyone else looking at this branch?” If the answer is yes, take your hands off the keyboard and start thinking about a non-destructive way to make your changes (e.g., the
9 command). Otherwise, you’re safe to re-write history as much as you like. Force-pushingIf you try to push the rebased
2 flag, like so:
This overwrites the remote One of the only times you should be force-pushing is when you’ve performed a local cleanup after you’ve pushed a private feature branch to a remote repository (e.g., for backup purposes). This is like saying, “Oops, I didn’t really want to push that original version of the feature branch. Take the current one instead.” Again, it’s important that nobody is working off of the commits from the original version of the feature branch. Workflow walkthroughRebasing can be incorporated into your existing Git workflow as much or as little as your team is comfortable with. In this section, we’ll take a look at the benefits that rebasing can offer at the various stages of a feature’s development. The first step in any workflow that leverages
6 is to create a dedicated branch for each feature. This gives you the necessary branch structure to safely utilize rebasing:
Local cleanupOne of the best ways to incorporate rebasing into your workflow is to clean up local, in-progress features. By periodically performing an interactive rebase, you can make sure each commit in your feature is focused and meaningful. This lets you write your code without worrying about breaking it up into isolated commits—you can fix it up after the fact. When calling
6, you have two options for the new base: The feature’s parent branch (e.g.,
By specifying
7 as the new base, you’re not actually moving the branch—you’re just interactively re-writing the 3 commits that follow it. Note that this will not incorporate upstream changes into the
0 branch.
If you want to re-write the entire feature using this method, the
9 command can be useful to find the original base of the
0 branch. The following returns the commit ID of the original base, which you can then pass to
6:
This use of interactive rebasing is a great way to introduce
6 into your workflow, as it only affects local branches. The only thing other developers will see is your finished product, which should be a clean, easy-to-follow feature branch history. But again, this only works for private feature branches. If you’re collaborating with other developers via the same feature branch, that branch is public, and you’re not allowed to re-write its history. There is no
9 alternative for cleaning up local commits with an interactive rebase. Incorporating upstream changes into a featureIn the Conceptual Overview section, we saw how a feature branch can incorporate upstream changes from
9 or
6. Merging is a safe option that preserves the entire history of your repository, while rebasing creates a linear history by moving your feature branch onto the tip of This use of
6 is similar to a local cleanup (and can be performed simultaneously), but in the process it incorporates those upstream commits from Keep in mind that it’s perfectly legal to rebase onto a remote branch instead of For example, if you and another developer named John added commits to the
0 branch, your repository might look like the following after fetching the remote
0 branch from John’s repository:
You can resolve this fork the exact same way as you integrate upstream changes from
0 with
5, or rebase your local
0 onto the tip of
5.
Note that this rebase doesn’t violate the Golden Rule of Rebasing because only your local
0 commits are being moved—everything before that is untouched. This is like saying, “add my changes to what John has already done.” In most circumstances, this is more intuitive than synchronizing with the remote branch via a merge commit. By default, the
9 command performs a merge, but you can force it to integrate the remote branch with a rebase by passing it the
0 option. Reviewing a feature with a pull requestIf you use pull requests as part of your code review process, you need to avoid using
6 after creating the pull request. As soon as you make the pull request, other developers will be looking at your commits, which means that it’s a public branch. Re-writing its history will make it impossible for Git and your teammates to track any follow-up commits added to the feature. Any changes from other developers need to be incorporated with
9 instead of
6. For this reason, it’s usually a good idea to clean up your code with an interactive rebase before submitting your pull request. Integrating an approved featureAfter a feature has been approved by your team, you have the option of rebasing the feature onto the tip of the
9 to integrate the feature into the main code base. This is a similar situation to incorporating upstream changes into a feature branch, but since you’re not allowed to re-write commits in the
9 to integrate the feature. However, by performing a rebase before the merge, you’re assured that the merge will be fast-forwarded, resulting in a perfectly linear history. This also gives you the chance to squash any follow-up commits added during a pull request.
If you’re not entirely comfortable with
6, you can always perform the rebase in a temporary branch. That way, if you accidentally mess up your feature’s history, you can check out the original branch and try again. For example:
SummaryAnd that’s all you really need to know to start rebasing your branches. If you would prefer a clean, linear history free of unnecessary merge commits, you should reach for
6 instead of
9 when integrating changes from another branch. On the other hand, if you want to preserve the complete history of your project and avoid the risk of re-writing public commits, you can stick with
9. Either option is perfectly valid, but at least now you have the option of leveraging the benefits of
6. Khi nào sử dụng git Rebase hơn là git merge?Ban sử dụng git rebase nếu như bạn muốn các sự thay đổi thuộc về branch của bạn luôn luôn là mới nhất. Và bạn có thể log một cách có hệ thống dễ nhìn, dễ tracking sao này. Bạn sử dụng git merge nếu bạn muốn sắp xếp các commit theo mặc định. Khi nào thì dùng git Rebase?Git Rebase là một chức năng được dùng khi gắn nhánh đã hoàn thành công việc vào nhánh gốc . Về mặt nội dung thì là việc điều chỉnh nhánh công việc gắn vào với nhánh gốc nên các commit sẽ được đăng kí theo thứ tự gắn vào . Chính vì thế sẽ có đặc trưng là dễ nhìn hơn sau khi xác nhận commit . Rebase and merge là gì?Merge và Rebase là 2 công cụ để trộn 2 branch trong Git, mục đích sử dụng cho những tính huống khác nhau. Git pull là gì?Git Pull Lệnh git pull được sử dụng để nhận các bản cập nhật từ từ xa. Lệnh này là sự kết hợp của git fetch và git merge, có nghĩa là khi chúng ta sử dụng git pull, nó sẽ nhận các bản cập nhật từ kho lưu trữ từ xa (git fetch) và ngay lập tức áp dụng các thay đổi mới nhất trong local của bạn (git merge). |