Làm thế nào để sửa lỗi cam kết với chi nhánh Git sai?


621

Tôi chỉ thực hiện một cam kết hoàn toàn tốt cho chi nhánh sai. Làm cách nào để hoàn tác cam kết cuối cùng trong nhánh chính của mình và sau đó thực hiện các thay đổi tương tự và đưa chúng vào nhánh nâng cấp của tôi?

Câu trả lời:


975

Nếu bạn chưa đẩy các thay đổi của mình, bạn cũng có thể thực hiện đặt lại mềm:

git reset --soft HEAD^

Điều này sẽ hoàn nguyên cam kết, nhưng đưa các thay đổi đã cam kết trở lại vào chỉ mục của bạn. Giả sử các chi nhánh tương đối cập nhật với nhau, git sẽ cho phép bạn thực hiện kiểm tra vào chi nhánh khác, trong đó bạn có thể chỉ cần cam kết:

git checkout branch
git commit

Nhược điểm là bạn cần nhập lại tin nhắn cam kết của mình.


10
lưu ý rằng thiết lập lại mềm để lại các thay đổi của bạn được tổ chức và sẵn sàng cam kết. làm tôi hơi bối rối khi IDE của tôi không hiển thị các tệp trở về trạng thái đã sửa đổi sau khi thiết lập lại mềm.
mtjhax

9
sửa chữa hoàn hảo, thực sự đã có một vài cam kết cũng như vậy ^^ và bam tất cả là hấp dẫn
pablo

8
Cảm ơn. Điều này đã cứu tôi hai lần. Nếu các chi nhánh hơi khác nhau, sau khi thiết lập lại và trước khi thanh toán, bạn có thể phải bỏ các thay đổi của mình trước khi bạn có thể kiểm tra chi nhánh khác. Áp dụng lại stash sau khi thanh toán
Kirby

17
Người dùng zsh: bạn có thể thấy mình cần phải thoát ^ như vậy:git reset --soft HEAD\^
Stephen Fuhry

54
Nếu bạn nhận được nhiều hơn? trong dòng lệnh Windows của bạn, hãy sử dụng dấu ngoặc kép để bao quanh HEAD ^ như vậy: git reset --soft "HEAD ^"
Nate Cook

141

4 năm muộn về chủ đề này, nhưng điều này có thể hữu ích cho ai đó.

Nếu bạn quên tạo một chi nhánh mới trước khi cam kết và cam kết tất cả với chủ, bất kể bạn đã thực hiện bao nhiêu lần cam kết, cách tiếp cận sau đây dễ dàng hơn:

git stash                       # skip if all changes are committed
git branch my_feature
git reset --hard origin/master
git checkout my_feature
git stash pop                   # skip if all changes were committed

Bây giờ bạn có nhánh chủ của bạn bằng origin/mastervà tất cả các cam kết mới được bật my_feature. Lưu ý rằng đó my_featurelà một chi nhánh địa phương, không phải là một chi nhánh từ xa.


Cảm ơn câu trả lời. Bây giờ tôi đang sử dụng egit và tôi tự hỏi liệu tôi có thể hoàn thành điều tương tự hay không bằng cách làm như sau: 1) Đổi tên 'chủ' hiện tại thành 'my_feature'. 2) Tái tạo 'chủ' địa phương từ 'nguồn gốc / chủ'. Tôi không chắc chắn những gì egit đang thực hiện trong các hoạt động này nhưng đây dường như là một giải pháp khả thi
mjj1409

Tại sao hợp nhất? bạn có thể tạo các chi nhánh trực tiếp trên master, sau đó thiết lập lại masterđể origin/master.
caesarsol

1
Đó là phần thú vị nhất: bạn không cần một số cam kết, vì origin/masterđã có trên cam kết bạn muốn đặt lại tại! Tuy nhiên, khoản tín dụng cho tiền boa là trang này: github.com/blog/ từ
caesarsol

4
Đây phải là câu trả lời được chấp nhận. Đơn giản, rõ ràng, đơn giản, hoạt động bất kể số lượng cam kết và chỉ sử dụng chức năng Git cơ bản. Tôi đã làm những bước này với TortoiseGit. Cảm ơn! :)
Ian Grainger

1
Tôi nghĩ rằng đây là câu trả lời tốt nhất, nhưng nó có một hạn chế. Nó chỉ giúp nếu bạn vừa mới kéo từ xa. Và nó giả sử bạn có một điều khiển từ xa để bắt đầu. Nếu bạn chỉ có các nhánh cục bộ "chính" và sửa lỗi tính năng mới của mình, câu trả lời đúng duy nhất là khó thiết lập lại trên tổng thể đếm lại một số lần xác nhận nhất định.
pauljohn32

111

Nếu bạn có một bản sao làm việc (chưa sửa đổi)

Để khôi phục một cam kết (đảm bảo bạn lưu ý hàm băm của cam kết cho bước tiếp theo):

git reset --hard HEAD^

Để kéo cam kết đó vào một nhánh khác:

git checkout other-branch
git cherry-pick COMMIT-HASH

Nếu bạn đã sửa đổi hoặc không theo dõi các thay đổi

Cũng lưu ý rằng git reset --hardsẽ giết mọi thay đổi chưa được theo dõi và sửa đổi mà bạn có thể có, vì vậy nếu bạn có những thay đổi bạn có thể thích:

git reset HEAD^
git checkout .

git rev-parse BRANCH_NAMEđể có được sha.
wilmustell

12
Nếu bạn quên ghi chú băm trước, chỉ cần sử dụng git reflog show <branch>!
Cascabel

2
@Jefromi Tôi đã sợ ở đó một phút.
Ian Hunter

13
Để có cảm giác an toàn hơn, trước tiên hãy thực hiện chọn cherry trên nhánh chính xác và chỉ sau đó đặt lại nhánh sai.
Tuổi Mooij

1
Ngoài ra, trong trường hợp thay đổi không được theo dõi, người ta có thể git stashtrước khi thiết lập lại và sử dụng git stash popsau đó để khôi phục chúng, vì vậy không cần phải lo sợ về --hardphần này
Clemens Klein-Robbenhaar

20

Nếu bạn đã đẩy các thay đổi của mình, bạn sẽ cần phải thực hiện lần đẩy tiếp theo sau khi đặt lại ĐẦU.

git reset --hard HEAD^
git merge COMMIT_SHA1
git push --force

Cảnh báo: thiết lập lại cứng sẽ hoàn tác mọi sửa đổi không được cam kết trong bản sao làm việc của bạn, trong khi lực đẩy sẽ ghi đè hoàn toàn trạng thái của nhánh từ xa với trạng thái hiện tại của nhánh cục bộ.

Chỉ trong trường hợp, trên Windows (sử dụng dòng lệnh Windows, không phải Bash), thực tế là bốn ^^^^thay vì một, vì vậy nó

git reset --hard HEAD^^^^

6
Lưu ý rằng bạn không nên ép buộc vào một nhánh mà người khác đang sử dụng trừ khi thực sự cần thiết - nếu không họ sẽ không thể đẩy cho đến khi họ nổi loạn. Tuy nhiên, nếu bạn là nhà phát triển duy nhất sử dụng git, điều này vẫn ổn.
Blair Holloway

2
Hoặc trừ khi bạn nhận ra đủ nhanh trước khi bất kỳ ai khác thực hiện các cam kết sai lầm.
Michael Mior

Nếu có nhiều hơn một lần cam kết, bạn có thể chỉ định cam kết bạn cần: git reset --hard COMMIT_HASH git push --force
David Cramblett

17

Gần đây tôi đã làm điều tương tự, nơi tôi vô tình cam kết thay đổi thành chủ, khi tôi đáng lẽ phải cam kết với chi nhánh khác. Nhưng tôi đã không thúc ép bất cứ điều gì.

Nếu bạn vừa cam kết với chi nhánh sai và không thay đổi bất cứ điều gì kể từ đó và không bị đẩy sang repo, thì bạn có thể làm như sau:

// rewind master to point to the commit just before your most recent commit.
// this takes all changes in your most recent commit, and turns them into unstaged changes. 
git reset HEAD~1 

// temporarily save your unstaged changes as a commit that's not attached to any branch using git stash
// all temporary commits created with git stash are put into a stack of temporary commits.
git stash

// create other-branch (if the other branch doesn't already exist)
git branch other-branch

// checkout the other branch you should have committed to.
git checkout other-branch

// take the temporary commit you created, and apply all of those changes to the new branch. 
//This also deletes the temporary commit from the stack of temp commits.
git stash pop

// add the changes you want with git add...

// re-commit your changes onto other-branch
git commit -m "some message..."

LƯU Ý: trong ví dụ trên, tôi đã tua lại 1 lần xác nhận với git reset HEAD ~ 1. Nhưng nếu bạn muốn tua lại n cam kết, thì bạn có thể thực hiện git reset HEAD ~ n.

Ngoài ra, nếu bạn đã kết thúc sai chi nhánh và cuối cùng cũng viết thêm một số mã trước khi nhận ra rằng bạn đã cam kết với chi nhánh sai, thì bạn có thể sử dụng git stash để lưu công việc đang thực hiện của mình:

// save the not-ready-to-commit work you're in the middle of
git stash 

// rewind n commits
git reset HEAD~n 

// stash the committed changes as a single temp commit onto the stack. 
git stash 

// create other-branch (if it doesn't already exist)
git branch other-branch

// checkout the other branch you should have committed to.
git checkout other-branch

// apply all the committed changes to the new branch
git stash pop

// add the changes you want with git add...

// re-commit your changes onto the new branch as a single commit.
git commit -m "some message..."

// pop the changes you were in the middle of and continue coding
git stash pop

LƯU Ý: Tôi đã sử dụng trang web này làm tài liệu tham khảo https://www.clearvision-cm.com/blog/what-to-do-when-you-commit-to-the-wrong-git-branch/


Điều tương tự cũng xảy ra với tôi, tôi đã thực hiện một vài thay đổi trong chủ, nhưng tôi nên thực hiện ở chi nhánh mới và gửi PR, cuối cùng tôi chỉ làm một git checkout -b new_branchquyền từ đó, cam kết vẫn nguyên vẹn, chỉ cần thúc đẩy và tạo ra một PR, đã không ' t phải cam kết lại.
Nishchal Gautam

11

Vì vậy, nếu kịch bản của bạn là bạn đã cam kết masternhưng có nghĩa là cam kết another-branch(có thể có hoặc không tồn tại) nhưng bạn vẫn chưa thúc đẩy, thì điều này khá dễ khắc phục.

// if your branch doesn't exist, then add the -b argument 
git checkout -b another-branch
git branch --force master origin/master

Bây giờ tất cả các cam kết của bạn mastersẽ được trên another-branch.

Được nuôi dưỡng bằng tình yêu từ: http://haacked.com/archive/2015/06/29/git-migrate/


dường như là cách tiếp cận đơn giản nhất! Không chắc chắn tại sao rất ít tình yêu và upwote
keligijus

4
Điều này dường như không làm việc cho tôi. another-branchđã tồn tại Trong trường hợp này, nó chỉ thu được các cam kết mà tôi đã thực hiện và không đưa chúng vào another-branch.
Giselle Serate

6

Để xây dựng trên này câu trả lời, trong trường hợp bạn có nhiều cam kết để di chuyển từ, ví dụ như developđể new_branch:

git checkout develop # You're probably there already
git reflog # Find LAST_GOOD, FIRST_NEW, LAST_NEW hashes
git checkout new_branch
git cherry-pick FIRST_NEW^..LAST_NEW # ^.. includes FIRST_NEW
git reflog # Confirm that your commits are safely home in their new branch!
git checkout develop
git reset --hard LAST_GOOD # develop is now back where it started

1
Tôi đã có ba lần hoàn nguyên, và câu hỏi này dường như đã kéo mông tôi ra khỏi lửa. Cảm ơn!
Holdenweb

3

Nếu bạn gặp phải vấn đề này và bạn có Visual Studio, bạn có thể làm như sau:

Nhấp chuột phải vào chi nhánh của bạn và chọn View History:

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

Nhấp chuột phải vào cam kết bạn muốn quay lại. Và hoàn nguyên hoặc thiết lập lại khi cần thiết.

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


3

Đối với nhiều cam kết trên nhánh sai

Nếu đối với bạn, đó chỉ là khoảng 1 cam kết, thì có rất nhiều giải pháp đặt lại dễ dàng khác có sẵn. Đối với tôi, tôi đã có khoảng 10 lần cam kết được thực hiện masterthay vì, hãy gọi nó branch_xyzvà tôi không muốn mất lịch sử cam kết.

Những gì bạn có thể làm và những gì đã cứu tôi đã sử dụng câu trả lời này làm tài liệu tham khảo, sử dụng quy trình 4 bước, đó là -

  1. Tạo một nhánh tạm thời mới từ master
  2. Hợp nhất vào chi nhánh ban đầu dự định cho các cam kết, nghĩa là branch_xyz
  3. Hoàn tác cam kết master
  4. Xóa chi nhánh tạm thời.

Dưới đây là các bước trên chi tiết -

  1. Tạo một chi nhánh mới từ master(nơi tôi đã vô tình thực hiện rất nhiều thay đổi)

    git checkout -b temp_branch_xyz
    

    Lưu ý: -bcờ được sử dụng để tạo chi nhánh mới
    Chỉ để xác minh xem chúng tôi có đúng không, tôi sẽ làm nhanh git branchđể đảm bảo rằng chúng tôi đang ở trong temp_branch_xyzchi nhánh và git logkiểm tra xem chúng tôi có xác nhận đúng không.

  2. Hợp nhất nhánh tạm thời vào nhánh ban đầu dự định cho các xác nhận, nghĩa là branch_xyz.
    Đầu tiên, chuyển sang nhánh ban đầu tức là branch_xyz(Bạn có thể cần git fetchnếu bạn không có)

    git checkout branch_xyz
    

    Lưu ý: Không sử dụng -bcờ
    Bây giờ, hãy hợp nhất nhánh tạm thời vào nhánh chúng tôi hiện đang thanh toánbranch_xyz

    git merge temp_branch_xyz
    

    Bạn có thể phải quan tâm đến một số xung đột ở đây, nếu có. Bạn có thể đẩy (tôi sẽ) hoặc chuyển sang các bước tiếp theo, sau khi hợp nhất thành công.

  3. Hoàn tác các cam kết vô tình về masterviệc sử dụng câu trả lời này làm tài liệu tham khảo, trước tiên hãy chuyển sangmaster

    git checkout master
    

    sau đó hoàn tác lại để khớp với điều khiển từ xa (hoặc với cam kết cụ thể, nếu bạn muốn)

    git reset --hard origin/master
    

    Một lần nữa, tôi sẽ làm git logtrước và sau chỉ để đảm bảo rằng những thay đổi dự định có hiệu lực.

  4. Xóa bằng chứng, đó là xóa chi nhánh tạm thời. Đối với điều này, trước tiên bạn cần kiểm tra nhánh mà temp đã được hợp nhất vào, tức là branch_xyz(Nếu bạn tiếp tục mastervà thực hiện lệnh bên dưới, bạn có thể nhận được a error: The branch 'temp_branch_xyz' is not fully merged), vì vậy hãy

    git checkout branch_xyz
    

    và sau đó xóa bằng chứng về sự rủi ro này

    git branch -d temp_branch_xyz
    

Có bạn đi.


1

Nếu chi nhánh bạn muốn áp dụng các thay đổi của mình đã tồn tại ( ví dụ: phát triển chi nhánh ), hãy làm theo các hướng dẫn được cung cấp bởi fotanus bên dưới, sau đó:

git checkout develop
git rebase develop my_feature # applies changes to correct branch
git checkout develop # 'cuz rebasing will leave you on my_feature
git merge develop my_feature # will be a fast-forward
git branch -d my_feature

Và rõ ràng bạn có thể sử dụng tempbranch hoặc bất kỳ tên chi nhánh nào khác thay vì my_feature nếu bạn muốn.

Ngoài ra, nếu có thể, hãy trì hoãn stash pop (áp dụng) cho đến khi bạn sáp nhập tại chi nhánh mục tiêu của mình.


Tôi nghĩ rằng lệnh đầu tiên (thanh toán phát triển) là không cần thiết ... rebase sẽ chỉ kiểm tra "my_feature" như điều đầu tiên nó làm.
JoelFan

Ngoài ra, bạn có thể bỏ tham số "my_feature" của lệnh "rebase" (vì bạn đã kiểm tra "my_feature"). bạn cũng có thể bỏ qua tham số "phát triển" của "hợp nhất" (vì bạn đã thanh toán "phát triển")
JoelFan

1

Đối với tôi, điều này đã được giải quyết bằng cách hoàn nguyên cam kết mà tôi đã đẩy, sau đó chọn anh đào cam kết với chi nhánh khác.

git checkout branch_that_had_the_commit_originally
git revert COMMIT-HASH
git checkout branch_that_was_supposed_to_have_the_commit
git cherry pick COMMIT-HASH

Bạn có thể sử dụng git logđể tìm băm chính xác và bạn có thể đẩy những thay đổi này bất cứ khi nào bạn muốn!

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.