Làm thế nào tôi có thể di chuyển trở lại vị trí trước đó? (Đầu tách rời) & Hoàn tác cam kết


179

Trong Git, tôi đã cố gắng thực hiện squash commitbằng cách sáp nhập vào một nhánh khác và sau đó đặt lại HEADvị trí trước đó thông qua:

git reset origin/master

Nhưng tôi cần phải bước ra khỏi đây. Làm thế nào tôi có thể di chuyển trở lại vị trí trước đó?

Tôi có đoạn SHA-1 ( 23b6772) của cam kết mà tôi cần chuyển nó sang. Làm thế nào tôi có thể quay lại cam kết này?


12
CHÍNH chỉ là một con trỏ đến vị trí hiện tại của bạn (hoặc sửa đổi để chính xác). git checkout 23b6772nên làm.
Quản trị viên của Yaroslav


1
@YaroslavAdmin Không nó nên không . Kiểm tra một cam kết trực tiếp lý do đã tách ra trạng thái CHÍNH (vì các nhánh theo dõi từ xa không thể tự kiểm tra và tự động trì hoãn cam kết mà chúng chỉ đến khi bạn cố gắng thực hiện như OP đã làm) Ngoài ra, xin lỗi vì cần thiết bình luận :-) Tôi hy vọng vấn đề ban đầu đã được giải quyết ...
RomainValeri 24/03/19

Câu trả lời:


397

Trước khi trả lời, hãy thêm một số nền tảng, giải thích đây HEADlà gì .

First of all what is HEAD?

HEADchỉ đơn giản là một tham chiếu đến cam kết hiện tại (mới nhất) trên nhánh hiện tại.
Chỉ có thể có một lần duy nhất HEADtại bất kỳ thời điểm nào (không bao gồm git worktree).

Nội dung của HEADđược lưu trữ bên trong .git/HEADvà nó chứa 40 byte SHA-1 của cam kết hiện tại.


detached HEAD

Nếu bạn không tham gia vào cam kết mới nhất - có nghĩa HEADlà chỉ đến một cam kết trước đó trong lịch sử, nó được gọi detached HEAD.

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

Trên dòng lệnh, nó sẽ trông như thế này - SHA-1 thay vì tên chi nhánh vì HEADnó không trỏ đến đầu của nhánh hiện tại:

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

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


Một vài lựa chọn về cách phục hồi từ một ĐẦU tách ra:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

Điều này sẽ kiểm tra chi nhánh mới chỉ vào cam kết mong muốn.
Lệnh này sẽ kiểm tra một cam kết nhất định.
Tại thời điểm này, bạn có thể tạo một nhánh và bắt đầu làm việc từ thời điểm này.

# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# Create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

Bạn luôn có thể sử dụng refloglà tốt.
git reflog sẽ hiển thị bất kỳ thay đổi nào đã cập nhật HEADvà kiểm tra mục nhập reflog mong muốn sẽ đặt HEADlại cho cam kết này.

Mỗi khi sửa đổi ĐẦU sẽ có một mục mới trong reflog

git reflog
git checkout HEAD@{...}

Điều này sẽ đưa bạn trở lại cam kết mong muốn của bạn

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


git reset --hard <commit_id>

"Di chuyển" ĐẦU của bạn trở lại cam kết mong muốn.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
  • Lưu ý: ( Kể từ Git 2.7 ), bạn cũng có thể sử dụng git rebase --no-autostash.

git revert <sha-1>

"Hoàn tác" phạm vi cam kết hoặc cam kết đã cho.
Lệnh đặt lại sẽ "hoàn tác" mọi thay đổi được thực hiện trong cam kết đã cho.
Một cam kết mới với bản vá hoàn tác sẽ được cam kết trong khi cam kết ban đầu cũng sẽ vẫn còn trong lịch sử.

# Add a new commit with the undo of the original one.
# The <sha-1> can be any commit(s) or commit range
git revert <sha-1>

Lược đồ này minh họa lệnh nào làm gì.
Như bạn có thể thấy ở đó, reset && checkoutsửa đổi HEAD.

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


Nếu bạn không tham gia vào cam kết mới nhất - có nghĩa là CHÍNH đang chỉ đến một cam kết trước đó trong lịch sử, thì nó được gọi là ĐẦU tách ra trừ khi cam kết trước đó trong lịch sử là đỉnh của một nhánh khác. Theo kinh nghiệm của tôi, bạn có thể nói rằng bạn bị tách ra nếu CHÍNH không chỉ vào một cam kết cũng được chỉ ra bởi bất kỳ chi nhánh nào. Điều này không áp dụng cho các thẻ.
Tim

Bạn có thể ở trong vị trí tách rời và đồng thời có một nhánh có cùng cam kết với phần đầu của nhánh này. Tôi không hiểu nhận xét của bạn
CodeWizard

3
Tôi có vấn đề với việc bạn sử dụng đánh dấu mã nội tuyến cho các tiêu đề :)
jub0bs

Không thể tìm thấy bất kỳ cách tốt hơn để nhấn mạnh nó. cảm thấy tự do để chỉnh sửa. bạn được chào đón nhiều hơn
CodeWizard

22

Làm

git reset 23b6772

Để xem nếu bạn ở đúng vị trí:

git status

Bạn sẽ thấy một cái gì đó

Trên nhánh chính Chi nhánh của bạn đứng sau 'origin / master' bởi 17 lần xác nhận và có thể được chuyển tiếp nhanh.

Sau đó viết lại lịch sử trên điều khiển từ xa của bạn để phản ánh sự thay đổi:

git push --force-with-lease // a useful command @oktober mentions in comments

1
HÃY CẨN THẬN TUYỆT VỜI với git push --force. Trong nhiều tình huống, nó sẽ khiến bạn trở thành người ít phổ biến nhất trong nhóm trong một thời gian ngắn ....
Kay V

để thêm vào ghi chú ở trên, tôi đã xem qua trích dẫn này tại about.gitlab.com/blog/2014/11/26/keep-your-code-protected và phải thêm nó: "Một lệnh git đẩy - lực lượng duy nhất có thể dễ dàng hủy hoại một ngày đối với nhiều người: [186 Jenkins] kho lưu trữ có các đầu chi nhánh được tua lại để chỉ ra các cam kết cũ hơn và thực tế, các cam kết mới hơn đã bị đặt sai sau khi đẩy git xấu. " - nhà phát triển rất không phổ biến ....
Kay V

2
@KayV hãy nhìn vào git push --force-with-lease(điều Thoughtbot: thoughtbot.com/blog/git-push-force-with-lease )
oktober

1
Cờ hữu ích, @ tháng mười, và một bài viết tốt. Cảm ơn vì đã thêm nó ở đây và đưa tôi về nó.
Kay V

1
cảm ơn bạn! điều này đã giúp tôi bỏ qua một sự hợp nhất xấu. kể từ khi sáp nhập không phản ứng giống như cách revertcam kết, tôi thấy mình trong một tình huống vô cùng khó khăn. force-with-leaseđã cho tôi sự tự tin để viết lại lịch sử git của chi nhánh mà không ảnh hưởng đến công việc của người khác. dũng cảm!
anon58192932

11

Giải pháp nhanh nhất có thể (chỉ 1 bước)

Sử dụng git checkout -

Bạn sẽ thấy Switched to branch <branch_name>. Xác nhận đó là chi nhánh bạn muốn.


Giải thích ngắn gọn: lệnh này sẽ di chuyển TRƯỚC về vị trí cuối cùng của nó. Xem lưu ý về kết quả ở cuối câu trả lời này.


Mnemonic: phương pháp này rất giống với việc sử dụng cd -để quay lại thư mục đã truy cập trước đó của bạn. Cú pháp và các trường hợp áp dụng là một kết hợp khá tốt (ví dụ: nó hữu ích khi bạn thực sự muốn TRƯỚC trở lại vị trí cũ).


Giải pháp có phương pháp hơn (2 bước, nhưng đáng nhớ)

Cách tiếp cận nhanh chóng giải quyết câu hỏi của OP. Nhưng điều gì sẽ xảy ra nếu tình huống của bạn hơi khác một chút: giả sử bạn đã khởi động lại Bash sau đó thấy mình bị tách ra. Trong trường hợp đó, đây là 2 bước đơn giản, dễ nhớ.

1. Chọn chi nhánh bạn cần

Sử dụng git branch -v

Bạn thấy một danh sách các chi nhánh địa phương hiện có. Lấy tên chi nhánh phù hợp với nhu cầu của bạn.

2. Di chuyển đầu đến nó

Sử dụng git checkout <branch_name>

Bạn sẽ thấy Switched to branch <branch_name>. Sự thành công!


Kết quả

Với bất kỳ phương pháp nào, giờ đây bạn có thể tiếp tục thêm và cam kết công việc của mình như trước: những thay đổi tiếp theo của bạn sẽ được theo dõi <branch_name>.

Lưu ý rằng cả hai git checkout -git checkout <branch_name>sẽ cung cấp hướng dẫn bổ sung nếu bạn đã cam kết thay đổi trong khi CHÍNH bị tách ra.


Điều này không hoạt động vì nếu tôi làm (giả sử rằng 8acc968 là CHÍNH ~ 2) git checkout 8acc968thì git branch -vMyBranchtrong danh sách bên dưới ... nhưng sau đó git checkout MyBranchxóa các nhận xét của tôi.
đặc biệt

Xin chào @amuliar - git checkout 8acc968sẽ kiểm tra một cam kết, không phải chi nhánh. Nếu MyBranchcó những cam kết bạn muốn, hãy thử git checkout MyBranch. Nếu nó không chứa các thay đổi trong cam kết 8acc968, bạn sẽ cần hợp nhất các thay đổi đó sau khi kiểm tra chi nhánh.
Kay V

Cảm ơn câu trả lời! Tôi đã làm git checkoutđể xem một cam kết trước đó và muốn quay lại cam kết mới nhất. Nhưng không có hash hash mới nhất, tôi đã mất khá nhiều. Giải pháp này là hoàn hảo cho tình huống của tôi!
zyy

4

Câu hỏi có thể được đọc là:

Tôi đang ở trong trạng thái tách rời với HEADtại 23b6772và gõ git reset origin/master(vì tôi muốn squash). Bây giờ tôi đã thay đổi suy nghĩ của tôi, làm thế nào để tôi quay trở lại HEADđược tại 23b6772?

Câu trả lời đơn giản là: git reset 23b6772

Nhưng tôi đánh vào câu hỏi này vì tôi chán việc gõ (sao chép và dán) cam kết băm hoặc viết tắt của nó mỗi lần tôi muốn tham khảo trước đó HEADvà đã Googling để xem liệu có bất kỳ loại tốc ký nào không.

Hóa ra là có!

git reset -(hoặc trong trường hợp của tôi git cherry-pick -)

Mà tình cờ giống như cd -trở về thư mục hiện tại trước đó trong * nix! Vì vậy, tôi đã học được hai điều với một viên đá.


0

Khi bạn chạy lệnh git checkout commit_idthì HEAD tách ra 13ca5593d(say commit-id)và nhánh sẽ có sẵn lâu hơn.

Di chuyển trở lại vị trí trước đó chạy bước lệnh khôn ngoan -

  1. git pull origin branch_name (nói chủ)
  2. git checkout branch_name
  3. git pull origin branch_name

Bạn sẽ trở lại vị trí trước đó với một cam kết được cập nhật từ kho lưu trữ từ xa.


0

Hôm nay, tôi đã kiểm tra nhầm một cam kết và bắt đầu thực hiện nó, thực hiện một số cam kết ở trạng thái CHÍNH. Sau đó, tôi đẩy đến nhánh từ xa bằng lệnh sau:

git push origin HEAD: <My-remote-branch>

Sau đó

git checkout <My-remote-branch>

Sau đó

git pull

Cuối cùng tôi đã nhận được tất cả những thay đổi trong chi nhánh của mình mà tôi đã thực hiện khi tách ra.


0

Đây có thể không phải là một giải pháp kỹ thuật, nhưng nó hoạt động. (nếu bất kỳ ai trong số đồng đội của bạn có cùng chi nhánh tại địa phương)

Giả sử tên chi nhánh của bạn là chi nhánh-xxx .

Các bước để giải quyết:

  • Đừng cập nhật hoặc kéo - không có gì
  • Chỉ cần tạo một nhánh mới ( nhánh-yyy ) từ nhánh-xxx trên máy của anh ấy
  • Đó là tất cả, tất cả các thay đổi hiện tại của bạn sẽ nằm trong chi nhánh mới này ( chi nhánh-yyy ). Bạn có thể tiếp tục công việc của bạn với chi nhánh này.

Lưu ý: Một lần nữa, đây không phải là một giải pháp kỹ thuật, nhưng nó sẽ giúp chắc chắ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.