Di chuyển (các) cam kết gần đây nhất đến một chi nhánh mới với Git


4985

Tôi muốn chuyển một số cam kết cuối cùng mà tôi đã cam kết thành thạo đến một chi nhánh mới và đưa chủ trở lại trước khi các cam kết đó được thực hiện. Thật không may, Git-fu của tôi chưa đủ mạnh, có giúp được gì không?

Tức là làm thế nào tôi có thể đi từ đây

master A - B - C - D - E

cái này

newbranch     C - D - E
             /
master A - B 

114
Lưu ý: Tôi đã hỏi câu hỏi ngược lại ở đây
Stewol

3
eddmann.com/posts/ từ cái này hoạt động
Sagar Naliyapara

7
Có phải các ý kiến ​​ở đây bị thanh trừng? Tôi hỏi bởi vì trong chuyến thăm hai tháng một lần của tôi cho câu hỏi này, tôi luôn cuộn theo nhận xét đó.
Tejas Kale

Câu trả lời:


6452

Di chuyển đến một chi nhánh hiện có

Nếu bạn muốn di chuyển các cam kết của mình đến một chi nhánh hiện có , nó sẽ trông như thế này:

git checkout existingbranch
git merge master         # Bring the commits here
git checkout master
git reset --keep HEAD~3  # Move master back by 3 commits.
git checkout existingbranch

Các --keeptùy chọn lưu giữ bất kỳ thay đổi không bị giam mà bạn có thể có trong các tập tin không liên quan, hoặc hủy bỏ nếu những thay đổi này sẽ phải ghi đè - tương tự như những gì git checkoutlàm. Nếu nó hủy bỏ, git stashcác thay đổi và thử lại của bạn hoặc sử dụng --hardđể mất các thay đổi (ngay cả từ các tệp không thay đổi giữa các lần xác nhận!)

Chuyển đến một chi nhánh mới

Phương thức này hoạt động bằng cách tạo một nhánh mới với lệnh đầu tiên ( git branch newbranch) nhưng không chuyển sang nó. Sau đó, chúng tôi quay trở lại chi nhánh hiện tại (chính) và chuyển sang chi nhánh mới để tiếp tục làm việc.

git branch newbranch      # Create a new branch, containing all current commits
git reset --keep HEAD~3   # Move master back by 3 commits (Make sure you know how many commits you need to go back)
git checkout newbranch    # Go to the new branch that still has the desired commits
# Warning: after this it's not safe to do a rebase in newbranch without extra care.

Nhưng hãy chắc chắn có bao nhiêu cam kết quay trở lại. Ngoài ra, thay vì HEAD~3, bạn chỉ có thể cung cấp hàm băm của cam kết (hoặc tham chiếu như origin/master) mà bạn muốn hoàn nguyên về, ví dụ:

git reset --keep a1b2c3d4

CẢNH BÁO: Với phiên bản Git 2.0 trở lên, nếu sau này bạn có git rebasenhánh mới trên nhánh gốc ( master), bạn có thể cần một --no-fork-pointtùy chọn rõ ràng trong quá trình rebase để tránh mất các cam kết bạn đã di chuyển từ nhánh chính. Có branch.autosetuprebase alwaysthiết lập làm cho điều này nhiều khả năng. Xem câu trả lời của John Mellor để biết chi tiết.


249
Và đặc biệt, đừng cố gắng quay lại xa hơn điểm mà lần cuối bạn đẩy cam kết sang một kho lưu trữ khác mà từ đó người khác có thể đã rút.
Greg Hewgill

107
Tự hỏi nếu bạn có thể giải thích TẠI SAO điều này hoạt động. Đối với tôi, bạn đang tạo một chi nhánh mới, loại bỏ 3 cam kết khỏi chi nhánh cũ mà bạn vẫn đang tiếp tục và sau đó kiểm tra chi nhánh bạn đã thực hiện. Vì vậy, làm thế nào để các cam kết bạn loại bỏ kỳ diệu xuất hiện trong chi nhánh mới?
Jonathan Dumaine

142
@Jonathan Dumaine: Bởi vì tôi đã tạo ra nhánh mới trước khi xóa các xác nhận khỏi nhánh cũ. Họ vẫn ở đó trong chi nhánh mới.
sykora

86
các nhánh trong git chỉ là các điểm đánh dấu trong lịch sử, không có gì được nhân bản, tạo hoặc xóa (ngoại trừ các điểm đánh dấu)
knittl

218
Cũng lưu ý: Đừng làm điều này với những thay đổi không được cam kết trong bản sao làm việc của bạn! Điều này chỉ cắn tôi! :(
Adam T Ink

1039

Đối với những người tự hỏi tại sao nó hoạt động (như tôi lúc đầu):

Bạn muốn quay lại C, và di chuyển D và E sang nhánh mới. Đây là những gì nó trông giống như lúc đầu:

A-B-C-D-E (HEAD)
        ↑
      master

Sau git branch newBranch:

    newBranch
        ↓
A-B-C-D-E (HEAD)
        ↑
      master

Sau git reset --hard HEAD~2:

    newBranch
        ↓
A-B-C-D-E (HEAD)
    ↑
  master

Vì một nhánh chỉ là một con trỏ, chủ chỉ vào lần xác nhận cuối cùng. Khi bạn tạo newBranch , bạn chỉ cần tạo một con trỏ mới cho lần xác nhận cuối cùng. Sau đó, sử dụng git resetbạn di chuyển con trỏ chủ trở lại hai lần xác nhận. Nhưng vì bạn không di chuyển newBranch , nên nó vẫn trỏ đến cam kết ban đầu.


56
Tôi cũng cần phải thực hiện một git push origin master --forcethay đổi để hiển thị trong kho lưu trữ chính.
Dženan

9
Câu trả lời này khiến cho các cam kết bị mất: lần sau bạn git rebase, 3 lần xác nhận sẽ bị loại bỏ newbranch. Xem câu trả lời của tôi để biết chi tiết và các lựa chọn thay thế an toàn hơn.
John Mellor

14
@ John, thật vớ vẩn. Nổi loạn mà không biết những gì bạn đang làm khiến cam kết bị mất. Nếu bạn mất các cam kết, tôi xin lỗi bạn, nhưng câu trả lời này đã không làm mất các cam kết của bạn. Lưu ý rằng origin/masterkhông xuất hiện trong sơ đồ trên. Nếu bạn đẩy đến origin/mastervà sau đó thực hiện các thay đổi ở trên, chắc chắn, mọi thứ sẽ trở nên buồn cười. Nhưng đó là một vấn đề "Bác sĩ, thật đau lòng khi tôi làm điều này". Và nó nằm ngoài phạm vi cho những gì câu hỏi ban đầu hỏi. Tôi đề nghị bạn viết câu hỏi của riêng bạn để khám phá kịch bản của bạn thay vì đánh cắp câu hỏi này.
Ryan Lundy

1
@ John, trong câu trả lời của bạn, bạn đã nói "Đừng làm điều này! git branch -t newbranch". Quay lại và đọc câu trả lời một lần nữa. Không ai đề nghị làm điều đó.
Ryan Lundy

1
@Kyralessa, chắc chắn, nhưng nếu bạn nhìn vào sơ đồ trong câu hỏi, rõ ràng là họ muốn newbranchđược dựa trên masterchi nhánh địa phương hiện tại của họ . Sau khi thực hiện câu trả lời được chấp nhận, khi người dùng bắt đầu chạy git rebasevào newbranch, git sẽ nhắc nhở họ rằng họ quên đặt nhánh ngược dòng, vì vậy họ sẽ chạy git branch --set-upstream-to=mastersau đó git rebasevà gặp vấn đề tương tự. Họ cũng có thể sử dụng git branch -t newbranchở nơi đầu tiên.
John Mellor

455

Nói chung...

Phương pháp được phơi bày bởi sykora là lựa chọn tốt nhất trong trường hợp này. Nhưng đôi khi không phải là dễ nhất và nó không phải là một phương pháp chung. Đối với phương pháp chung, sử dụng git cherry-pick :

Để đạt được những gì OP muốn, quy trình gồm 2 bước:

Bước 1 - Lưu ý cam kết từ chủ bạn muốn trên newbranch

Hành hình

git checkout master
git log

Lưu ý băm của (nói 3) cam kết bạn muốn trên newbranch. Ở đây tôi sẽ sử dụng:
C commit: 9aa1233
D commit: 453ac3d
E commit:612ecb3

Lưu ý: Bạn có thể sử dụng bảy ký tự đầu tiên hoặc toàn bộ băm xác nhận

Bước 2 - Đặt chúng vào newbranch

git checkout newbranch
git cherry-pick 612ecb3
git cherry-pick 453ac3d
git cherry-pick 9aa1233

HOẶC (trên Git 1.7.2+, sử dụng phạm vi)

git checkout newbranch
git cherry-pick 612ecb3~1..9aa1233

git cherry-pick áp dụng ba cam kết đó cho newbranch.


13
Không phải OP đang cố gắng chuyển từ chủ sang newbranch sao? Nếu bạn chọn cherry trong khi ở chế độ chính, bạn sẽ thêm vào nhánh chính - thực tế là thêm các cam kết mà nó đã có. Và nó không di chuyển trở lại đầu chi nhánh đến B. Hoặc có điều gì đó tinh tế và tuyệt vời mà tôi không nhận được?
RaveTheTadpole

6
Điều này hoạt động rất tốt nếu bạn vô tình phạm phải nhánh không chính chủ, khi bạn nên tạo một nhánh tính năng mới.
julianc

5
+1 cho cách tiếp cận hữu ích trong một số tình huống. Điều này là tốt nếu bạn chỉ muốn kéo các cam kết của riêng bạn (được xen kẽ với những người khác) vào một chi nhánh mới.
Tyler V.

8
Đó là câu trả lời tốt hơn. Bằng cách này bạn có thể di chuyển cam kết đến bất kỳ chi nhánh.
skywinder

8
Là thứ tự hái anh đào quan trọng?
kon tâm lý

328

Một cách khác để làm điều này, chỉ sử dụng 2 lệnh. Cũng giữ cho cây làm việc hiện tại của bạn nguyên vẹn.

git checkout -b newbranch # switch to a new branch
git branch -f master HEAD~3 # make master point to some older commit

Phiên bản cũ - trước khi tôi biết vềgit branch -f

git checkout -b newbranch # switch to a new branch
git push . +HEAD~3:master # make master point to some older commit 

Có khả năng pushđể .là một thủ thuật rất hay biết.


1
Thư mục hiện tại. Tôi đoán điều này sẽ chỉ hoạt động nếu bạn đang ở trong một thư mục hàng đầu.
aragaer

1
Sự thúc đẩy cục bộ là gây cười, nhưng về sự phản ánh, nó khác với git branch -fở đây như thế nào?
jthill

2
@Gerardottton .là giám đốc hiện tại. git có thể đẩy tới các URL NHỚ hoặc GIT. path to local directoryđược hỗ trợ cú pháp URL Git. Xem phần GIT URLS trong git help clone.
suy yếu

31
Tôi không biết tại sao điều này không được đánh giá cao hơn. Chết đơn giản, và không có nguy cơ nhỏ nhưng tiềm ẩn của git reset - hard.
Godsmith

4
@Godsmith Tôi đoán là mọi người thích ba lệnh đơn giản hơn hai lệnh khó hiểu hơn một chút. Ngoài ra, các câu trả lời được bình chọn hàng đầu nhận được nhiều lượt ủng hộ hơn do bản chất được hiển thị đầu tiên.
JS_Riddler

323

Hầu hết các câu trả lời trước là sai nguy hiểm!

KHÔNG làm điều này:

git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch

Vì lần sau khi bạn chạy git rebase(hoặc git pull --rebase) 3 cam kết đó sẽ bị loại bỏ trong âm thầm newbranch! (xem giải thích bên dưới)

Thay vào đó hãy làm điều này:

git reset --keep HEAD~3
git checkout -t -b newbranch
git cherry-pick ..HEAD@{2}
  • Đầu tiên, nó loại bỏ 3 cam kết gần đây nhất ( --keepgiống như --hard, nhưng an toàn hơn, vì thất bại thay vì vứt bỏ những thay đổi không được cam kết).
  • Sau đó nó rẽ nhánh newbranch.
  • Sau đó, anh đào chọn 3 cam kết trở lại newbranch. Vì chúng không còn được tham chiếu bởi một chi nhánh, nên nó sử dụng reflog của git : HEAD@{2}là cam kết HEADđược sử dụng để đề cập đến 2 thao tác trước đây, tức là trước khi chúng tôi 1. kiểm tra newbranchvà 2. được sử dụng git resetđể loại bỏ 3 cam kết.

Cảnh báo: reflog được bật theo mặc định, nhưng nếu bạn đã tắt nó theo cách thủ công (ví dụ: bằng cách sử dụng kho git "trần"), bạn sẽ không thể lấy lại 3 lần xác nhận sau khi chạy git reset --keep HEAD~3.

Một thay thế không dựa vào reflog là:

# newbranch will omit the 3 most recent commits.
git checkout -b newbranch HEAD~3
git branch --set-upstream-to=oldbranch
# Cherry-picks the extra commits from oldbranch.
git cherry-pick ..oldbranch
# Discards the 3 most recent commits from oldbranch.
git branch --force oldbranch oldbranch~3

(nếu bạn thích bạn có thể viết @{-1}- nhánh đã kiểm tra trước đó - thay vì oldbranch).


Giải thích kỹ thuật

Tại sao sẽ git rebaseloại bỏ 3 cam kết sau ví dụ đầu tiên? Đó là bởi vì git rebasekhông có đối số cho phép --fork-pointtùy chọn theo mặc định, sử dụng reflog cục bộ để cố gắng mạnh mẽ chống lại nhánh ngược dòng bị đẩy mạnh.

Giả sử bạn đã phân nhánh gốc / chủ khi nó chứa các xác nhận M1, M2, M3, sau đó tự thực hiện ba lần xác nhận:

M1--M2--M3  <-- origin/master
         \
          T1--T2--T3  <-- topic

nhưng sau đó ai đó viết lại lịch sử bằng cách đẩy gốc / chủ để loại bỏ M2:

M1--M3'  <-- origin/master
 \
  M2--M3--T1--T2--T3  <-- topic

Sử dụng reflog cục bộ của bạn, git rebasecó thể thấy rằng bạn đã rẽ nhánh từ một phiên bản trước đó của nhánh gốc / nhánh chính và do đó, các cam kết M2 và M3 không thực sự là một phần của nhánh chủ đề của bạn. Do đó, nó giả định một cách hợp lý rằng vì M2 đã bị xóa khỏi nhánh ngược dòng, bạn không còn muốn nó trong nhánh chủ đề của mình nữa khi nhánh chủ đề bị từ chối:

M1--M3'  <-- origin/master
     \
      T1'--T2'--T3'  <-- topic (rebased)

Hành vi này có ý nghĩa, và nói chung là điều đúng đắn khi làm lại.

Vì vậy, lý do mà các lệnh sau không thành công:

git branch -t newbranch
git reset --hard HEAD~3
git checkout newbranch

là bởi vì họ để lại reflog ở trạng thái sai. Git thấy newbranchnhư đã chia hai ra khỏi chi nhánh thượng nguồn ở một phiên bản bao gồm 3 cam kết, thì reset --hardviết lại lịch sử của thượng nguồn để loại bỏ các cam kết, và thời gian để sau khi bạn chạy git rebasenó loại bỏ chúng giống như bất kỳ khác cam kết rằng đã bị xóa khỏi thượng lưu.

Nhưng trong trường hợp cụ thể này, chúng tôi muốn 3 cam kết đó được coi là một phần của nhánh chủ đề. Để đạt được điều đó, chúng ta cần tách ra khỏi thượng nguồn trong lần sửa đổi trước đó không bao gồm 3 cam kết. Đó là những gì các giải pháp được đề xuất của tôi làm, do đó cả hai đều để lại reflog ở trạng thái chính xác.

Để biết thêm chi tiết, xem định nghĩa --fork-pointtrong tài liệu cơ sở git rebasegit merge-base .


15
Câu trả lời này nói "KHÔNG làm điều này!" trên một cái gì đó mà không ai đề nghị làm.
Ryan Lundy

4
Hầu hết mọi người không viết lại lịch sử đã xuất bản, đặc biệt là trên master. Vì vậy, họ không sai một cách nguy hiểm.
Rời

4
@Kyralessa, -tbạn đang đề cập đến git branchxảy ra ngầm nếu bạn đã git config --global branch.autosetuprebase alwaysthiết lập. Ngay cả khi bạn không, tôi đã giải thích cho bạn rằng vấn đề tương tự xảy ra nếu bạn thiết lập theo dõi sau khi thực hiện các lệnh này, vì OP có thể dự định sẽ đưa ra câu hỏi của họ.
John Mellor

2
@RockLee, vâng, cách chung để khắc phục các tình huống đó là tạo một nhánh mới (newbranch2) từ điểm bắt đầu an toàn sau đó chọn tất cả các cam kết bạn muốn giữ (từ badnewbranch sang newbranch2). Chọn anh đào sẽ cung cấp cho các cam kết băm mới, vì vậy bạn sẽ có thể khởi động lại newbranch2 một cách an toàn (và bây giờ có thể xóa badnewbranch).
John Mellor

2
@Walf, bạn đã hiểu nhầm: git rebase được thiết kế để mạnh mẽ chống lại những người thượng lưu có lịch sử viết lại. Thật không may, các tác dụng phụ của sự mạnh mẽ đó ảnh hưởng đến tất cả mọi người, ngay cả khi cả họ và thượng nguồn của họ không bao giờ viết lại lịch sử.
John Mellor

150

Giải pháp đơn giản hơn nhiều bằng cách sử dụng git stash

Đây là một giải pháp đơn giản hơn nhiều cho các cam kết sai chi nhánh. Bắt đầu trên nhánh mastercó ba lần xác nhận sai:

git reset HEAD~3
git stash
git checkout newbranch
git stash pop

Khi nào sử dụng cái này?

  • Nếu mục đích chính của bạn là quay trở lại master
  • Bạn muốn giữ thay đổi tập tin
  • Bạn không quan tâm đến các tin nhắn trên các cam kết nhầm
  • Bạn chưa đẩy
  • Bạn muốn điều này dễ dàng để ghi nhớ
  • Bạn không muốn các biến chứng như các nhánh tạm thời / mới, tìm và sao chép băm cam kết và các vấn đề đau đầu khác

Cái này làm gì, theo số dòng

  1. Hoàn tác ba lần xác nhận cuối cùng (và tin nhắn của họ) master, nhưng vẫn giữ nguyên tất cả các tệp đang hoạt động
  2. Loại bỏ tất cả các thay đổi tệp làm việc, làm cho mastercây làm việc chính xác bằng trạng thái CHÍNH ~ 3
  3. Chuyển sang một chi nhánh hiện có newbranch
  4. Áp dụng các thay đổi được lưu vào thư mục làm việc của bạn và xóa stash

Bây giờ bạn có thể sử dụng git addgit commitnhư bạn thường làm. Tất cả các cam kết mới sẽ được thêm vào newbranch.

Cái này không làm

  • Nó không để lại các nhánh tạm thời làm lộn xộn cây của bạn
  • Nó không lưu giữ các thông báo cam kết nhầm, vì vậy bạn sẽ cần thêm một thông điệp cam kết mới vào cam kết mới này
  • Cập nhật! Sử dụng mũi tên lên để cuộn qua bộ đệm lệnh của bạn để áp dụng lại cam kết trước đó với thông điệp cam kết của nó (cảm ơn @ARK)

Bàn thắng

OP tuyên bố mục tiêu là "lấy lại chủ trước khi những cam kết đó được thực hiện" mà không làm mất các thay đổi và giải pháp này thực hiện điều đó.

Tôi làm điều này ít nhất một lần một tuần khi tôi vô tình thực hiện các cam kết mới master thay vì develop. Thông thường tôi chỉ có một cam kết để khôi phục trong trường hợp sử dụng git reset HEAD^trên dòng 1 là cách đơn giản hơn để khôi phục chỉ một cam kết.

Đừng làm điều này nếu bạn đẩy các thay đổi của chủ lên thượng nguồn

Một số người khác có thể đã kéo những thay đổi đó. Nếu bạn chỉ viết lại chủ địa phương của mình thì không có tác động gì khi nó bị ngược dòng, nhưng việc đẩy lịch sử viết lại cho cộng tác viên có thể gây đau đầu.


4
Cảm ơn, rất vui vì tôi đã đọc qua / qua rất nhiều để đến đây, vì đó cũng là một trường hợp sử dụng khá phổ biến đối với tôi. Có phải chúng ta không điển hình?
Jim Mack

6
Tôi nghĩ rằng chúng tôi hoàn toàn điển hình và "rất tiếc tôi đã thành thạo do nhầm lẫn" là trường hợp sử dụng phổ biến nhất cho nhu cầu hoàn nguyên một số ít hoặc ít hơn các cam kết. May mắn là giải pháp này rất đơn giản. Tôi đã ghi nhớ ngay bây giờ.
Slam

9
Đây phải là câu trả lời được chấp nhận. Thật đơn giản, dễ hiểu và dễ nhớ
Sina Madani

1
Tôi không nghĩ rằng việc đâm là cần thiết. Tôi chỉ làm mà không có và làm việc tốt.
Một Campos

1
Bạn cũng có thể dễ dàng lấy lại tin nhắn cam kết của mình, nếu bạn tình cờ có chúng trong lịch sử CLI (dòng lệnh) của bạn. Tôi tình cờ có cả lệnh git addgit commitlệnh mà tôi đã sử dụng vì vậy tất cả những gì tôi phải làm là nhấn mũi tên lên và nhập một vài lần và bùng nổ! Tất cả mọi thứ đã trở lại, nhưng trên nhánh bên phải bây giờ.
Luke Gedeon

30

Điều này không "di chuyển" chúng theo nghĩa kỹ thuật nhưng nó có tác dụng tương tự:

A--B--C  (branch-foo)
 \    ^-- I wanted them here!
  \
   D--E--F--G  (branch-bar)
      ^--^--^-- Opps wrong branch!

While on branch-bar:
$ git reset --hard D # remember the SHAs for E, F, G (or E and G for a range)

A--B--C  (branch-foo)
 \
  \
   D-(E--F--G) detached
   ^-- (branch-bar)

Switch to branch-foo
$ git cherry-pick E..G

A--B--C--E'--F'--G' (branch-foo)
 \   E--F--G detached (This can be ignored)
  \ /
   D--H--I (branch-bar)

Now you won't need to worry about the detached branch because it is basically
like they are in the trash can waiting for the day it gets garbage collected.
Eventually some time in the far future it will look like:

A--B--C--E'--F'--G'--L--M--N--... (branch-foo)
 \
  \
   D--H--I--J--K--.... (branch-bar)

1
Bạn không thể sử dụng rebasecho cùng một thứ?
Bergi

Có, bạn có thể sử dụng thay thế rebasetrên nhánh tách ra trong kịch bản trên.
Sukima

24

Để làm điều này mà không cần viết lại lịch sử (nghĩa là nếu bạn đã đẩy các cam kết):

git checkout master
git revert <commitID(s)>
git checkout -b new-branch
git cherry-pick <commitID(s)>

Cả hai nhánh sau đó có thể được đẩy mà không cần lực!


Nhưng sau đó, bạn phải đối phó với kịch bản hoàn nguyên, tùy thuộc vào hoàn cảnh của bạn, có thể khó khăn hơn rất nhiều. Nếu bạn hoàn nguyên một cam kết trên nhánh, Git vẫn sẽ thấy các cam kết đó đã diễn ra, vì vậy để hoàn tác điều đó, bạn phải hoàn nguyên lại hoàn nguyên. Điều này đốt cháy khá nhiều người, đặc biệt là khi họ hoàn nguyên hợp nhất và cố gắng hợp nhất lại chi nhánh, chỉ để thấy rằng Git tin rằng nó đã hợp nhất chi nhánh đó (điều này hoàn toàn đúng).
Makoto

1
Đó là lý do tại sao tôi chọn những cam kết ở cuối, trên một nhánh mới. Bằng cách đó, git xem chúng như những cam kết mới, giải quyết vấn đề của bạn.
teh_senaus

Điều này nguy hiểm hơn vẻ bề ngoài của nó, vì bạn đang thay đổi trạng thái của lịch sử kho lưu trữ mà không thực sự hiểu ý nghĩa của trạng thái này.
Makoto

5
Tôi không tuân theo lập luận của bạn - quan điểm của câu trả lời này là bạn không thay đổi lịch sử, chỉ cần thêm các cam kết mới (điều này có hiệu quả hoàn tác lại các thay đổi). Những cam kết mới này có thể được đẩy và sáp nhập như bình thường.
teh_senaus

13

Chỉ có tình huống này:

Branch one: A B C D E F     J   L M  
                       \ (Merge)
Branch two:             G I   K     N

Tôi đã thực hiện:

git branch newbranch 
git reset --hard HEAD~8 
git checkout newbranch

Tôi đã cam kết rằng tôi sẽ là người đứng đầu, nhưng giờ đây tôi đã cam kết ...

Để chắc chắn hạ cánh đúng chỗ trong lịch sử, làm việc dễ dàng hơn với hàm băm của cam kết

git branch newbranch 
git reset --hard #########
git checkout newbranch

8

Làm thế nào tôi có thể đi từ đây

A - B - C - D - E 
                |
                master

cái này

A - B - C - D - E 
    |           |
    master      newbranch

Với hai lệnh

  • chi nhánh git -m chủ newbranch

cho

A - B - C - D - E 
                |
                newbranch

  • git chi nhánh B

cho

A - B - C - D - E
    |           |
    master      newbranch

Đúng, điều này hoạt động và khá dễ dàng. GUI Sourcetree có một chút nhầm lẫn về những thay đổi được thực hiện trong vỏ git, nhưng sau khi tìm nạp lại, mọi thứ lại ổn.
lars k.

Vâng, họ là như trong câu hỏi. Một vài sơ đồ đầu tiên được dự định tương đương với những câu hỏi trong câu hỏi, chỉ cần vẽ lại theo cách tôi muốn cho mục đích minh họa trong câu trả lời. Về cơ bản đổi tên nhánh chủ thành newbranch và tạo một nhánh chủ mới nơi bạn muốn.
Ivan

Tôi tin rằng đây là câu trả lời đúng.
Leonardo Herrera

4

Nếu bạn chỉ cần di chuyển tất cả các cam kết chưa được đánh dấu của mình sang một nhánh mới , thì bạn chỉ cần

  1. tạo một nhánh mới từ cái hiện tại:git branch new-branch-name

  2. đẩy chi nhánh mới của bạn :git push origin new-branch-name

  3. hoàn nguyên nhánh cũ (hiện tại) của bạn về trạng thái đẩy / ổn định cuối cùng:git reset --hard origin/old-branch-name

Một số người cũng có khác upstreamshơn origin, họ nên sử dụng thích hợpupstream


3

1) Tạo một nhánh mới, di chuyển tất cả các thay đổi của bạn sang new_branch.

git checkout -b new_branch

2) Sau đó quay trở lại chi nhánh cũ.

git checkout master

3) Làm git rebase

git rebase -i <short-hash-of-B-commit>

4) Sau đó, trình soạn thảo đã mở chứa 3 thông tin cam kết cuối cùng.

...
pick <C's hash> C
pick <D's hash> D
pick <E's hash> E
...

5) Thay đổi pickđể droptrong tất cả những cam kết 3. Sau đó lưu và đóng trình chỉnh sửa.

...
drop <C's hash> C
drop <D's hash> D
drop <E's hash> E
...

6) Bây giờ 3 cam kết cuối cùng được xóa khỏi nhánh hiện tại ( master). Bây giờ đẩy chi nhánh mạnh mẽ, với +dấu hiệu trước tên chi nhánh.

git push origin +master

2

Bạn có thể làm điều này chỉ là 3 bước đơn giản mà tôi đã sử dụng.

1) tạo chi nhánh mới nơi bạn muốn cam kết cập nhật gần đây.

git branch <branch name>

2) Tìm Id Cam kết gần đây cho cam kết trên chi nhánh mới.

git log

3) Sao chép ghi chú id mà danh sách cam kết gần đây nhất diễn ra trên đầu trang. để bạn có thể tìm thấy cam kết của bạn. bạn cũng tìm thấy điều này qua tin nhắn.

git cherry-pick d34bcef232f6c...

bạn cũng có thể cung cấp một số phạm vi của id xác nhận.

git cherry-pick d34bcef...86d2aec

Bây giờ công việc của bạn đã hoàn thành. Nếu bạn chọn đúng id và đúng nhánh thì bạn sẽ thành công. Vì vậy, trước khi làm điều này hãy cẩn thận. vấn đề khác có thể xảy ra.

Bây giờ bạn có thể đẩy mã của bạn

git push


0

Một cách khác để làm điều này:

[1] Đổi tên masterchi nhánh thành của bạn newbranch(giả sử bạn đang ở masterchi nhánh):

git branch -m newbranch

[2] Tạomaster chi nhánh từ cam kết mà bạn muốn:

git checkout -b master <seven_char_commit_id>

ví dụ: kiểm tra git -b master a34bc22

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.