Git: Làm thế nào để đè bẹp tất cả các cam kết trên nhánh


315

Tôi tạo chi nhánh mới từ master:

git checkout -b testbranch

Tôi thực hiện 20 cam kết vào nó.

Bây giờ tôi muốn dẹp 20 cam kết đó. Tôi làm điều đó với:

git rebase -i HEAD~20

Nếu tôi không biết có bao nhiêu cam kết thì sao? Có cách nào để làm một cái gì đó như:

git rebase -i all on this branch

6
Bạn có thể thực git rebase -i 58333012713fc168bd70ad00d191b3bdc601fa2dhiện một cuộc nổi loạn tương tác trong đó cam kết là cam kết cuối cùng không thay đổi
denns

@denns Sử dụng phương pháp này với cam kết cuối cùng trong nhánh mà bạn đang nổi loạn từ làm việc tuyệt vời. Cám ơn rất nhiều!
Joshua Pinter

Câu trả lời:


395

Một cách khác để xóa tất cả các cam kết của bạn là đặt lại chỉ mục thành chủ:

 git checkout yourBranch
 git reset $(git merge-base master yourBranch)
 git add -A
 git commit -m "one commit on yourBranch"

Điều này không hoàn hảo vì nó ngụ ý bạn biết chi nhánh "yourBranch" đến từ đâu.
Lưu ý: việc tìm kiếm nhánh gốc không dễ / có thể với Git ( cách trực quan thường dễ nhất , như được thấy ở đây ).


EDIT: bạn sẽ cần sử dụng git push --force


Karlotcha Hoa cho biết thêm trong các ý kiến :

Để thiết lập lại, bạn có thể làm

git reset $(git merge-base master $(git rev-parse --abbrev-ref HEAD)) 

[Điều đó] tự động sử dụng chi nhánh bạn hiện đang ở.
Và nếu bạn sử dụng nó, bạn cũng có thể sử dụng bí danh, vì lệnh không dựa vào tên nhánh .


2
Tốt hơn để kiểm tra để cam kết nơi YourBranchhiện đang có. Điều này sẽ được giữ YourBranchnguyên khi bạn làmreset
Eugen Konkov

1
@Abdurrahim Hoặc mở một git bash, và yo có thể sao chép-dán các lệnh thos!
VonC

3
Để thiết lập lại, bạn có thể làm git reset $(git merge-base master $(git rev-parse --abbrev-ref HEAD))để tự động sử dụng chi nhánh bạn hiện đang sử dụng. Và nếu bạn sử dụng nó, bạn cũng có thể sử dụng bí danh, vì lệnh không dựa vào tên nhánh.
Karlotcha Hoa

1
@Druska Đối với trường hợp phân nhánh simlpe, không, nó sẽ hoạt động tốt.
VonC

1
@Shimmy có, miễn là bạn buộc phải đẩy sau khi thiết lập lại: git push --force(và cảnh báo các đồng nghiệp của bạn nếu bạn là một số người làm việc trên chi nhánh đó)
VonC

112

Kiểm tra chi nhánh mà bạn muốn nén tất cả các cam kết thành một cam kết. Hãy nói rằng nó được gọi là feature_branch.

git checkout feature_branch

Bước 1:

Thực hiện thiết lập lại mềm của bạn origin/feature_branchvới masterchi nhánh địa phương của bạn (tùy thuộc vào nhu cầu của bạn, bạn cũng có thể đặt lại với nguồn gốc / chủ). Điều này sẽ đặt lại tất cả các cam kết bổ sung trong của bạn feature_branch, nhưng không thay đổi bất kỳ thay đổi tệp nào của bạn cục bộ.

git reset --soft master

Bước 2:

Thêm tất cả các thay đổi trong thư mục git repo của bạn, vào cam kết mới sẽ được tạo. Và cam kết tương tự với một tin nhắn.

git add -A && git commit -m "commit message goes here"


6
Đây là giải pháp đáng tin cậy nhất đối với tôi - không gây ra bất kỳ lỗi rebase nào cũng như hợp nhất các xung đột.
ANTARA

1
Cảnh báo: git add -A add MỌI THỨ bạn có trong thư mục cục bộ - vào chi nhánh.
David H

thích giải pháp này! đây chính xác là những gì tôi muốn
jacoballenwood

1
Giải pháp tốt nhất cho một noob - không phá hủy và chỉ có khoảnh khắc oops có thể kiểm tra quá nhiều như bí mật ứng dụng, v.v., điều đó không quan trọng nếu bạn có một tệp gitignore thích hợp
kkarakk

@NSduToit Câu trả lời ngắn gọn: Không, bạn không phải làm vậy. Sau khi thực hiện các bước được đề cập ở trên trong câu trả lời của tôi, bạn sẽ kết thúc với một cam kết với một số thay đổi mã. Bạn có thể nghĩ về nó giống như bất kỳ cam kết nào khác với một số thay đổi mã. Bạn có thể đẩy nó đến chi nhánh từ xa của bạn mà không cần -fcờ.
shanky

110

Những gì bạn đang làm là dễ bị lỗi. Cứ làm đi:

git rebase -i master

sẽ chỉ tự động khởi động lại các cam kết của chi nhánh của bạn đối với chủ mới nhất hiện tại.


5
cảm ơn, tôi hiểu rồi, nhưng tại sao hệ thống của tôi dễ bị lỗi
3803850

10
Có lẽ bởi vì nó dễ dàng để có được số sai?
Daniel Scott

13
Đồng ý đây là giải pháp tốt nhất của bạn. nhưng hãy theo liên kết này vì nó giải thích rõ hơn những gì bạn cần làm.
Christo

3
Thay vì xóa các xác nhận, bạn có thể hợp nhất nhánh thành chủ và thực hiện thiết lập lại git thành gốc / gốc để hủy bỏ tất cả các xác nhận. Điều đó sẽ cho phép bạn cam kết mã chưa được mã hóa hiện tại của mình vớicommit -am "the whole thing!"
Nurettin

2
@nurettin Tôi nghĩ rằng reset origin/masterphương pháp này thực sự tồi tệ vì nó giống như thực hiện các cam kết trực tiếp trên chủ - không có lịch sử 'hợp nhất chi nhánh', không có tùy chọn yêu cầu kéo. Câu trả lời của @WaZaA phù hợp hơn với quy trình làm việc bình thường mà tôi nghĩ
Drenai

79

Một cách đơn giản khác để làm điều này: đi vào nhánh gốc và làm a merge --squash. Lệnh này không thực hiện cam kết "đè bẹp". khi bạn làm điều đó, tất cả các thông điệp cam kết của bạn sẽ được thu thập.

$ git checkout master
$ git merge --squash yourBranch
$ git commit # all commit messages of yourBranch in one, really useful
 > [status 5007e77] Squashed commit of the following: ...

1
Thật. Tôi đã đề cập đến sự khác biệt giữa hợp nhất --squash và rebase -i trong stackoverflow.com/a/2427520/6309
VonC

1
Điều này hoạt động nếu bạn không muốn squash vào nhánh cha, chỉ cần tạo và chuyển sang một nhánh mới dựa trên nhánh cha và thực hiện squash hợp nhất vào đó.
Charlotte

Chúc mừng bạn đời, mẹo tuyệt vời!
Nestor Milyaev

đẹp! tôi tạo một nhánh "temp" tắt "master" trước tiên để nén "yourBranch" vào, sau đó hợp nhất "temp" thành "master".
lazieburd

34

Giả sử bạn đã phân nhánh từ chủ, bạn không cần phải thực yourBranchhiện bước thiết lập lại mọi lúc:

git checkout yourBranch
git reset --soft HEAD~$(git rev-list --count HEAD ^master)
git add -A
git commit -m "one commit on yourBranch"

Giải thích :

  • git rev-list --count HEAD ^masterđếm các cam kết kể từ khi bạn thực hiện nhánh tính năng của mình từ tổng thể, f.ex. 20.
  • git reset --soft HEAD~20sẽ thực hiện thiết lập lại mềm của 20 lần xác nhận cuối cùng. Điều này để lại những thay đổi của bạn trong các tệp, nhưng loại bỏ các xác nhận.

Sử dụng :

Trong .bash_profile của tôi, tôi đã thêm một bí danh gisquashđể làm điều này với một lệnh:

# squash all commits into one
alias gisquash='git reset --soft HEAD~$(git rev-list --count HEAD ^master)'

Sau khi thiết lập lại và cam kết bạn cần phải làm một git push --force .

Dấu :

Nếu bạn đang sử dụng Gitlab> = 11.0, bạn không cần phải làm điều này nữa vì nó có tùy chọn đè bẹp khi hợp nhất các nhánh. Tùy chọn nghiền Gitlab


15

Dựa trên việc đọc một số câu hỏi và câu trả lời về Stackoverflow về squash, tôi nghĩ rằng đây là một cách tốt để xóa tất cả các cam kết trên một nhánh:

git reset --soft $(git merge-base master YOUR_BRANCH) && git commit -am "YOUR COMMIT MESSAGE" && git rebase -i master

Đây là giả sử chủ là nhánh cơ sở.


1
Cảm ơn rất nhiều, công ty có rất nhiều hạn chế và không thể phản đối theo cách thông thường với một biên tập viên vì không thể tiết kiệm được. Cũng không thể sử dụng tính năng squash và merge trong git vì nhánh này chuyển đến dev dev để hợp nhất và anh ta không thích nó. 1 lót này làm việc và tiết kiệm đau đầu. Công việc tuyệt vời
L1ghtk3ira

10

Giải pháp cho những người thích nhấp chuột:

  1. Cài đặt sourcetree (miễn phí)

  2. Kiểm tra cam kết của bạn trông như thế nào. Nhiều khả năng bạn có một cái gì đó tương tự như thế này nhập mô tả hình ảnh ở đây

  3. Nhấp chuột phải vào cam kết của phụ huynh . Trong trường hợp của chúng tôi, nó là chi nhánh tổng thể.

nhập mô tả hình ảnh ở đây

  1. Bạn có thể xóa cam kết với lần trước bằng cách nhấp vào nút. Trong trường hợp của chúng tôi, chúng tôi phải nhấp 2 lần. Bạn cũng có thể thay đổi thông điệp cam kết nhập mô tả hình ảnh ở đây

  2. Kết quả thật tuyệt vời và chúng tôi đã sẵn sàng để đẩy! nhập mô tả hình ảnh ở đây

Lưu ý bên lề: Nếu bạn đang đẩy một phần cam kết của mình vào điều khiển từ xa, bạn phải sử dụng lực đẩy sau khi ép


Cảm ơn vì điều đó!
Pha lê

0

Một giải pháp khác là lưu tất cả các bản ghi cam kết vào một tệp

đăng nhập git> chi nhánh.log

Bây giờ Branch.log sẽ có tất cả id id từ khi bắt đầu .. cuộn xuống và thực hiện lần xác nhận đầu tiên (điều này sẽ khó khăn trong terminal) bằng cách sử dụng lần xác nhận đầu tiên

thiết lập lại git --soft

tất cả các cam kết sẽ bị nghiền nát


0

Git reset, như đã đề cập trong nhiều câu trả lời trước đây, cho đến nay là cách tốt nhất và đơn giản nhất để đạt được những gì bạn muốn. Tôi sử dụng nó trong quy trình làm việc sau đây:

(trên nhánh phát triển)

git fetch
git merge origin/master  #so development branch has all current changes from master
git reset origin/master  #will show all changes from development branch to master as unstaged
git gui # do a final review, stage all changes you really want
git commit # all changes in a single commit
git branch -f master #update local master branch
git push origin master #push it

0

Tất cả các thiết lập lại git này, cứng, mềm và mọi thứ khác được đề cập ở đây có thể đang hoạt động (nó không phù hợp với tôi) nếu bạn thực hiện các bước chính xác và một số loại thần.
Nếu bạn là Joe smo trung bình, hãy thử điều này:
Làm thế nào để sử dụng git merge --squash?


Cứu mạng tôi, và tôi sẽ đi chơi bóng quần, đã sử dụng nó 4 lần kể từ khi tôi phát hiện ra nó. Đơn giản, sạch sẽ và cơ bản là 1 comamnd. Nói ngắn gọn:


Nếu bạn ở trên một chi nhánh, hãy gọi nó là "my_new_feature", hãy phát triển và yêu cầu kéo của bạn có 35 lần xác nhận (hoặc nhiều lần) và bạn muốn nó là 1.

A. Hãy chắc chắn rằng chi nhánh của bạn được cập nhật, Tiếp tục phát triển, nhận bản mới nhất và hợp nhất và giải quyết mọi xung đột với "my_new_feature"
(bước này thực sự bạn nên thực hiện ngay khi bạn có thể mọi lúc mọi nơi)

B. Nhận bản phát triển mới nhất và phân nhánh đến một chi nhánh mới gọi nó là "my_new_feature_squashing"

C. ma thuật ở đây.
Bạn muốn đưa công việc của mình từ "my_new_feature" sang "my_new_feature_squashing"
Vì vậy, hãy làm (trong khi trên nhánh mới của bạn, chúng tôi đã tạo ra phát triển):
git merge --squash my_new_feature

Tất cả các thay đổi của bạn bây giờ sẽ nằm trên chi nhánh mới của bạn, vui lòng kiểm tra nó, sau đó chỉ cần thực hiện 1 cam kết duy nhất, đẩy, PR mới của chi nhánh đó - và chờ lặp lại vào ngày hôm sau.
Bạn không thích viết mã? :)


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.