Di chuyển con trỏ nhánh đến các cam kết khác nhau mà không cần thanh toán


760

Để di chuyển con trỏ nhánh của nhánh đã kiểm tra, người ta có thể sử dụng git reset --hardlệnh. Nhưng làm thế nào để di chuyển con trỏ nhánh của nhánh không được kiểm tra để trỏ đến một cam kết khác (giữ tất cả các thứ khác như nhánh từ xa được theo dõi)?


11
Âm thanh giống như tất cả những gì bạn muốn làm là một nhánh từ một cam kết khác với âm thanh mà nó được tạo ra từ bây giờ. Nếu sự hiểu biết của tôi là chính xác, thì tại sao bạn không đơn giản tạo ra một nhánh mới từ cam kết mà bạn muốn tạo nó từ việc sử dụng git branch <branch-name> <SHA-1-of-the-commit>và kết xuất nhánh cũ?
yasouser

6
@yasouser - Tôi không chắc chắn bất cứ điều gì bán phá giá chi nhánh "chính chủ" là một ý tưởng tốt.
Bulwersator

Câu trả lời:


578

Bạn có thể làm điều đó cho refs tùy ý. Đây là cách di chuyển một con trỏ nhánh:

git update-ref -m "reset: Reset <branch> to <new commit>" refs/heads/<branch> <commit>

Hình thức chung:

git update-ref -m "reset: Reset <branch> to <new commit>" <ref> <commit>

Bạn có thể chọn nits về thông điệp reflog nếu bạn thích - Tôi tin rằng branch -fmột là khác nhau từ reset --hardmột, và đây không phải là chính xác cả hai người.


39
Thông điệp tốt ở đâu? Nó được lưu trữ ở đâu và làm thế nào để đọc nó sau này?
Mot

4
LƯU Ý: Điều này không hoạt động trên các kho lưu trữ trần. Trên các kho lưu trữ trần, bạn phải sử dụng 'git chi nhánh -f master <commit>' để cập nhật chi nhánh (xem câu trả lời bên dưới).
Tháng Sáu Rhodes

37
Nếu, giống như tôi, bạn vô tình sử dụng <chi nhánh> thay vì refs / Heads / <chi nhánh>, bạn sẽ kết thúc với một tệp mới trong thư mục .git của mình tại .git / <chi nhánh> và bạn sẽ nhận được tin nhắn như "refname 'master' là mơ hồ" khi bạn cố gắng làm việc với nó. Bạn có thể xóa tệp khỏi thư mục .git để sửa.
David nhỏ

34
Nó đã không được giải thích cho sự hài lòng tại sao điều này là tốt hơn git branch -f. Cụ thể, phương pháp này dường như là: (A) khó sử dụng hơn (B) khó nhớ hơn và (C) nguy hiểm hơn
Steven Lu

10
"Chính xác nghĩa là gì bởi các ref tùy ý" - Chi nhánh không phải là loại ref duy nhất chỉ ra một cam kết. Có các thẻ và bạn cũng có thể tạo các ref tùy ý / whatevs / myref style refs mình không phải là nhánh cũng không phải thẻ. Tôi tin rằng cũng trả lời câu hỏi của Steven Lu về điều này có thể "tốt hơn". Tôi đồng ý chi nhánh -f là đơn giản nhất nếu bạn đang làm việc với các chi nhánh.
Adam A

964
git branch -f <branch-name> <new-tip-commit>

24
Hoặc cho refs tùy ý git update-ref -m "reset: Reset <branch> to <new commit>" <branch> <commit>,. (Bạn có thể chọn nits về thông điệp reflog nếu bạn thích - Tôi tin rằng branch -fmột là khác nhau từ reset --hardmột, và đây không phải là chính xác cả hai người.)
Cascabel

4
Jefromi, xin vui lòng viết một câu trả lời riêng biệt để bạn có thể nhận được phiếu bầu. :)
Mot

16
Đây là một câu trả lời tốt hơn vì nó xử lý 99% trường hợp và thực sự phù hợp với tài liệu. git help branchnói "-f, - Force Reset <Branchname> thành <startpoint> nếu <Branchname> đã tồn tại. Không có nhánh -f git từ chối thay đổi một nhánh hiện có."
AlexChaffee

12
Tôi đang làm git branch -f master <hash>và nó nói với tôi fatal: Cannot force update the current branch.Ummmm Tôi phải làm gì bây giờ, kiểm tra một số nhánh ngẫu nhiên khác trước khi tôi được phép sử dụng lệnh này?
Qwertie

20
Điều này sẽ không hoạt động nếu chi nhánh bạn đang cố gắng di chuyển là chi nhánh hiện tại của bạn ( HEADchỉ vào chi nhánh ).
Vladimir Panteleev

135

Bạn cũng có thể vượt qua git reset --hardmột tài liệu tham khảo cam kết.

Ví dụ:

git checkout branch-name
git reset --hard new-tip-commit

Tôi thấy tôi làm điều gì đó như thế này thường xuyên:

Giả sử lịch sử này

$ git log --decorate --oneline --graph
* 3daed46 (HEAD, master) New thing I shouldn't have committed to master
* a0d9687 This is the commit that I actually want to be master

# Backup my latest commit to a wip branch
$ git branch wip_doing_stuff

# Ditch that commit on this branch
$ git reset --hard HEAD^

# Now my changes are in a new branch
$ git log --decorate --oneline --graph
* 3daed46 (wip_doing_stuff) New thing I shouldn't have committed to master
* a0d9687 (HEAD, master) This is the commit that I actually want to be master

Điều này có ý nghĩa nhất ở chỗ người ta thường sử dụng ĐẦU hoặc ĐẦU ^ để di chuyển đầu nhánh trở lại đúng lúc. Vì vậy, điều này là phù hợp để xác định các cam kết phía trước.
justingordon

11
Điều này là tốt nếu cây làm việc của bạn sạch sẽ. Nếu bạn có nhiều thay đổi theo giai đoạn hoặc không theo giai đoạn, có lẽ tốt hơn nên làm git update-refnhư đã thảo luận ở trên.
một mọt sách được trả tiền

16
Bạn có nhận thấy rằng câu trả lời của bạn không có bất cứ điều gì không phải là một phần của câu hỏi không ?? - OP nói: nếu nó được kiểm tra ... bạn có thể sử dụng git reset --hard ...Không cần lặp lại ở đây! :-(
Robert Siemer

6
@Robert: Tôi không đồng ý. Câu hỏi không nói làm thế nào để sử dụng nó và điều này không. Thật tuyệt khi không phải đi tìm nó như thế nào.
Wilson F

7
@WilsonF, có lẽ thật tuyệt khi bạn tìm thấy điều này ở đây, nhưng nó không trả lời câu hỏi nào cả. Có thể đó là câu trả lời của một số câu hỏi khác, nhưng ở đây nó sai .
Robert Siemer

52

Chỉ để làm phong phú cuộc thảo luận, nếu bạn muốn chuyển myBranchchi nhánh sang cam kết hiện tại của mình , chỉ cần bỏ qua đối số thứ hai sau-f

Thí dụ:

git branch -f myBranch


Tôi thường làm điều này khi tôi rebaseở trạng thái ĐẦU tách rời :)


13

Trong gitk --all:

  • nhấp chuột phải vào cam kết bạn muốn
  • -> tạo chi nhánh mới
  • nhập tên của một chi nhánh hiện có
  • nhấn return trên hộp thoại xác nhận thay thế nhánh cũ của tên đó .

Coi chừng việc tạo lại thay vì sửa đổi chi nhánh hiện tại sẽ mất thông tin chi nhánh theo dõi . (Đây thường không phải là vấn đề đối với các trường hợp sử dụng đơn giản khi chỉ có một điều khiển từ xa và chi nhánh địa phương của bạn có cùng tên với chi nhánh tương ứng trong điều khiển từ xa. Xem bình luận để biết thêm chi tiết, cảm ơn @mbdevpl đã chỉ ra nhược điểm này.)

Sẽ thật tuyệt nếu gitkcó một tính năng trong đó hộp thoại có 3 tùy chọn: ghi đè, sửa đổi hiện có hoặc hủy bỏ.


Ngay cả khi bạn bình thường là một người nghiện dòng lệnh như tôi, git guigitkđược thiết kế khá độc đáo cho tập hợp con của việc sử dụng git mà họ cho phép. Tôi đặc biệt khuyên bạn nên sử dụng chúng cho những gì họ giỏi (nghĩa là chọn lọc những người đi vào / ra khỏi chỉ mục trong git gui, và cũng chỉ cam kết. (Ctrl-s để thêm một dòng đã ký .)

gitk là tuyệt vời để theo dõi một vài chi nhánh trong khi bạn sắp xếp các thay đổi của mình thành một chuỗi bản vá đẹp để gửi ngược dòng hoặc bất cứ điều gì khác mà bạn cần theo dõi những gì bạn đang ở giữa với nhiều chi nhánh.

Tôi thậm chí không mở trình duyệt tệp đồ họa, nhưng tôi thích gitk / git gui.


1
Quá dễ! Tôi có thể vừa chuyển đổi từ gitg sang gitk.
Michael Cole

Cách này, tuy nhiên, thông tin chi nhánh theo dõi bị mất.
mbdevpl

@mbdevpl: Tôi không thực sự là một chuyên gia git. Tôi nghĩ tôi hiểu ý của bạn, nhưng không phải là hàm ý. Tôi đã sử dụng điều này khá thường xuyên và vẫn có thể đẩy các nhánh đó đến các nhánh cùng tên trên một điều khiển từ xa. Sự liên kết giữa một chi nhánh và chi nhánh theo dõi từ xa của nó làm gì cho bạn?
Peter Cordes


1
@PeterCordes Ineed, khi tên chi nhánh không khớp với nó. Ngoài ra khi có nhiều hơn một điều khiển từ xa. Ngoài ra, khi bạn đang sử dụng dấu nhắc git để hiển thị trạng thái nhánh, nó sẽ hiển thị khoảng cách cam kết với nhánh theo dõi của bạn (nếu được đặt). Ngoài ra, git statusđầu ra bị ảnh hưởng. Ngoài ra, trong một số trường hợp git fetchgit pushsẽ không hoạt động mà không chỉ định rõ ràng từ xa nếu bạn không đặt nhánh theo dõi. Tôi không biết về tất cả các trường hợp, nhưng đối với tôi, nguyên tắc chung là để thuận tiện và nhanh chóng trong công việc, tốt hơn là nên theo dõi các chi nhánh theo thứ tự.
mbdevpl

7

Các giải pháp đề nghịgit branch -f branch-pointer-to-move new-pointer trong TortoiseGit :

  • "Nhật ký hiển thị Git"
  • Kiểm tra "Tất cả các chi nhánh"
  • Trên dòng bạn muốn con trỏ nhánh di chuyển đến (con trỏ mới):
    • Nhấp chuột phải, "Tạo chi nhánh tại phiên bản này"
    • Bên cạnh "Nhánh", nhập tên của nhánh cần di chuyển (nhánh-con trỏ để di chuyển)
    • Trong "Base On", kiểm tra xem con trỏ mới có đúng không
    • Kiểm tra "Lực lượng"
    • Đồng ý

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

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


4

Thành thật mà nói, tôi ngạc nhiên khi không ai nghĩ về git pushlệnh:

git push -f . <destination>:<branch>

Dấu chấm (.) Đề cập đến kho lưu trữ cục bộ và bạn có thể cần tùy chọn -f vì đích đến có thể là "phía sau đối tác từ xa" .

Mặc dù lệnh này được sử dụng để lưu các thay đổi của bạn trong máy chủ của bạn, nhưng kết quả hoàn toàn giống như khi di chuyển nhánh từ xa ( <branch>) sang cùng một cam kết như nhánh cục bộ ( <destination>)


Bạn cũng có thể làm điều này mà không -fđể tránh ghi đè bất cứ thứ gì cục bộ; chẳng hạn, git fetch origin && git push . origin/develop:developlà phiên bản không nhanh không cần thanh toán củagit checkout develop && git pull --ff-only
btown

1

Mở tệp .git/refs/heads/<your_branch_name>và thay đổi hàm băm được lưu trữ ở đó thành tệp bạn muốn di chuyển phần đầu của chi nhánh. Chỉ cần chỉnh sửa và lưu tệp với bất kỳ trình soạn thảo văn bản. Chỉ cần đảm bảo rằng nhánh cần sửa đổi không phải là nhánh hoạt động hiện tại.

Tuyên bố từ chối trách nhiệm: Có lẽ không phải là một cách được khuyến khích để làm điều đó, nhưng hoàn thành công việc.


1
Không chắc đây là cách hỗn loạn hay xấu xa để làm điều đó. 🤔 😉
Keith Russell

@KeithRussell có thể là cả hai: P
Guillermo Gutiérrez

0

Trong trường hợp cam kết bạn muốn trỏ đến trước nhánh hiện tại (phải là trường hợp trừ khi bạn muốn hoàn tác các cam kết cuối cùng của nhánh hiện tại), bạn chỉ cần thực hiện:

git merge <commit>

Câu hỏi hỏi về những việc cần làm nếu chi nhánh không được kiểm tra.
Keith Russell

Rất tiếc, tôi đã bỏ lỡ điểm đó. Trong trường hợp đó bạn có thể làm git push . <commit>:<branch>như đã đề xuất.
Jean Paul
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.