di chuyển cam kết (nhưng không được đẩy) thay đổi sang một chi nhánh mới sau khi kéo


460

Tôi đã thực hiện một chút công việc ("Chi nhánh của bạn đi trước 'nguồn gốc / chủ nhân' bằng 37 lần cam kết.") Mà thực sự nên đi vào chi nhánh của chính nó chứ không phải vào master. Những cam kết này chỉ tồn tại trên máy cục bộ của tôi và chưa được đẩy tới origin, nhưng tình hình hơi phức tạp ở chỗ các nhà phát triển khác đã và đang thực hiện origin/masternhững thay đổi đó.

Làm thế nào để tôi hồi tố di chuyển 37 cam kết địa phương của tôi lên một chi nhánh mới? Dựa trên các tài liệu, có vẻ như git rebase --onto my-new-branch masterhoặc ...origin/masternên làm điều này, nhưng cả hai chỉ cho tôi lỗi "gây tử vong: Cần một sửa đổi duy nhất". man git-rebasekhông nói gì về việc cung cấp bản sửa đổi rebasevà các ví dụ của nó không làm như vậy, vì vậy tôi không biết làm thế nào để khắc phục lỗi này.

(Lưu ý rằng đây là không một bản sao của Move hiện có, công việc uncommited đến một chi nhánh mới trong Git hoặc Làm thế nào để nhập các thay đổi không bị giam địa phương của tôi vào một chi nhánh Git? Như những câu hỏi đối phó với những thay đổi không bị giam trong cây lao động địa phương, không thay đổi mà có được cam kết tại địa phương.)


Kiểm tra giải pháp này . Có vẻ là dễ dàng và sạch sẽ.
Tony

Kiểm tra giải pháp này . Có vẻ là dễ dàng và sạch sẽ.
Tony

Câu trả lời:


518

Điều này sẽ ổn thôi, vì bạn chưa đẩy các cam kết của mình ở bất kỳ nơi nào khác và bạn có thể tự do viết lại lịch sử của chi nhánh sau đó origin/master. Đầu tiên tôi sẽ chạy một git fetch originđể đảm bảo rằng nó origin/masterđược cập nhật. Giả sử rằng bạn hiện đang trên master, bạn sẽ có thể làm:

git rebase origin/master

... sẽ phát lại tất cả các cam kết của bạn không origin/mastertham gia origin/master. Hành động mặc định của rebase là bỏ qua các cam kết hợp nhất (ví dụ: các cam kết mà bạn git pullcó thể đã giới thiệu) và nó sẽ chỉ thử áp dụng các bản vá được giới thiệu bởi mỗi cam kết của bạn origin/master. (Bạn có thể phải giải quyết một số xung đột trên đường đi.) Sau đó, bạn có thể tạo chi nhánh mới của mình dựa trên kết quả:

git branch new-work

... và sau đó đặt masterlại lưng của bạn thành origin/master:

# Use with care - make sure "git status" is clean and you're still on master:
git reset --hard origin/master

Khi làm điều này loại cành thao tác với git branch, git reset, vv Tôi thấy hữu ích khi thường xuyên nhìn vào cam kết đồ thị với gitk --allhoặc một công cụ tương tự, chỉ để kiểm tra mà tôi hiểu nơi tất cả các refs khác nhau đang trỏ.

Ngoài ra, bạn có thể vừa tạo một nhánh chủ đề dựa trên vị trí chủ của bạn ở vị trí đầu tiên ( git branch new-work-including-merges) và sau đó đặt lại masternhư trên. Tuy nhiên, vì nhánh chủ đề của bạn sẽ bao gồm các hợp nhất từ origin/mastervà bạn chưa thúc đẩy các thay đổi của mình, tôi khuyên bạn nên thực hiện một cuộc nổi loạn để lịch sử gọn gàng hơn. (Ngoài ra, khi cuối cùng bạn hợp nhất nhánh chủ đề của mình trở lại thành chủ, những thay đổi sẽ rõ ràng hơn.)


8
@Olie: Không, câu trả lời là đúng theo các giả định trong câu hỏi và những câu tôi đặt ra ở đầu câu trả lời. Các cam kết nên có trên một nhánh mới riêng biệt đã có sẵn master; rebase viết lại masternhánh để các cam kết mới được tuyến tính trên đỉnh origin/master, sau đó git branch new-worktạo một new-worknhánh trỏ vào đầu master(nhánh hiện tại) mà không chuyển nhánh hiện tại sang new-work. Vì vậy, bây giờ new-workchứa tất cả các cam kết mới. Sau đó, thiết lập lại di chuyển nhánh hiện tại (vẫn master) trở lại origin/master.
Mark Longair

1
@Quintesse: Tôi rất xin lỗi nếu bạn bị mất việc, nhưng tôi chắc chắn câu trả lời này là chính xác cho tình huống được mô tả bởi người hỏi ban đầu. . ) bạn sẽ có thể dễ dàng truy xuất nó thông qua glog reflog.
Mark Longair

5
@Olie: có lẽ là một cách giải thích tốt hơn: các nhánh trong git giống như các nhãn chỉ vào một cam kết cụ thể; chúng sẽ tự động được chuyển sang các xác nhận mới nếu bạn tạo chúng khi ở trên nhánh đó hoặc có thể được di chuyển bằng git resetnhiều cách khác. Điều git branch new-worknày chỉ nói rằng "tạo một nhánh chỉ vào cam kết này trong khi tôi vẫn ở nhánh hiện tại của mình (là chủ trong trường hợp này)". Vì vậy, không cần phải có lệnh di chuyển các cam kết từ chủ sang nhánh mới - bạn chỉ cần tạo một nhánh mới ở đó và khi bạn đặt lại chủ, nhánh mới sẽ rời khỏi nơi chủ nhân
Mark Longair

1
đến bữa tiệc muộn một chút nhưng @Olie, chỉ vì tình trạng git khi ở chi nhánh mới không hiển thị các cam kết trước chủ không có nghĩa là họ không thực sự ở đó (giả sử đó là lý do khiến bạn lo lắng). Hãy thử đẩy chi nhánh mới về nguồn gốc: bạn sẽ thấy các cam kết ở đó
Félix Gagnon-Grenier

2
@ FélixGagnon-Grenier, đừng lo lắng về "muộn" - luôn có người tìm kiếm những câu hỏi cũ và mọi sự làm rõ đều có ích. Cảm ơn! :)
Olie

148

Nếu bạn có số lượng cam kết thấp và bạn không quan tâm nếu chúng được kết hợp thành một cam kết lớn, thì điều này hoạt động tốt và không đáng sợ như khi thực hiện git rebase:

bỏ các tập tin (thay thế 1 bằng # xác nhận)

git reset --soft HEAD~1

tạo một chi nhánh mới

git checkout -b NewBranchName

thêm các thay đổi

git add -A

cam kết

git commit -m "Whatever"

5
Để hiển thị một biểu đồ dễ hiểu, vui lòng sử dụng git log --all --decorate --oneline --graph.
EliuX

Xin chào @EliuX - Tôi đang thiếu sự liên quan ở đây. Bạn có thể mở rộng?
Stachu

Đây là một cái gì đó hữu ích để kiểm tra xem bạn có đạt được kết quả mong muốn trong những gì bạn đã làm hay không
EliuX

4
Cảm ơn!! Đây là một giải pháp rất đơn giản và nó hoạt động hoàn hảo !!
Chris Sim

91

Tôi mắc kẹt với cùng một vấn đề. Tôi đã tìm thấy giải pháp dễ nhất mà tôi muốn chia sẻ.

1) Tạo chi nhánh mới với những thay đổi của bạn.

git checkout -b mybranch

2) (Tùy chọn) Đẩy mã chi nhánh mới trên máy chủ từ xa.

git push origin mybranch

3) Thanh toán trở lại chi nhánh chính.

git checkout master

4) Đặt lại mã nhánh chính với máy chủ từ xa và xóa cam kết cục bộ.

git reset --hard origin/master

10
Đó thực sự là cách dễ nhất
dhilt

4
Bạn có thể bỏ qua bước 2. Tôi giả sử rằng trong thời gian kể từ câu trả lời hàng đầu, git đã thay đổi và điều này không được phép trước đây.
Sebastian

Đây là câu trả lời tốt nhất theo ý kiến ​​của tôi.
Macindows

1
Câu trả lời này cần phải di chuyển lên đầu. Cảm ơn bạn.
amit

27

Một cách nữa giả định nhánh1 - là nhánh có các thay đổi được cam kết nhánh2 - là nhánh mong muốn

git fetch && git checkout branch1
git log

chọn id id mà bạn cần di chuyển

git fetch && git checkout branch2
git cherry-pick commit_id_first..commit_id_last
git push

Bây giờ hoàn nguyên các cam kết không được đánh dấu từ chi nhánh ban đầu

git fetch && git checkout branch1
git reset --soft HEAD~1

5
Cherry-pick thực sự là lệnh "sao chép / di chuyển một cam kết" tốt nhất, đặc biệt. khi lịch sử là hành lý cho mục đích của bạn.
John Neuhaus

Đây là câu trả lời thuận tiện nhất cho câu hỏi. Cảm ơn bạn đã ra lệnh!
Farah

bạn có thể cập nhật nhận xét cuối cùng của bạn trong đó 1 hoặc n là số lần xác nhận không được đánh dấu? Đây vẫn là một giải pháp thực sự tốt cho câu hỏi này.
chAlexey

9

Ngoài ra, ngay sau khi bạn cam kết với chi nhánh sai, hãy thực hiện các bước sau:

  1. git log
  2. git diff {previous to last commit} {latest commit} > your_changes.patch
  3. git reset --hard origin/{your current branch}
  4. git checkout -b {new branch}
  5. git apply your_changes.patch

Tôi có thể tưởng tượng rằng có một cách tiếp cận đơn giản hơn cho các bước một và hai.


6

Thế còn:

  1. Chi nhánh từ ĐẦU hiện tại.
  2. Hãy chắc chắn rằng bạn đang ở trên chủ , không phải chi nhánh mới của bạn.
  3. git reset trở lại cam kết cuối cùng trước khi bạn bắt đầu thay đổi.
  4. git pull để chỉ lấy lại các thay đổi từ xa mà bạn đã ném đi với thiết lập lại.

Hay nó sẽ phát nổ khi bạn cố gắng hợp nhất lại chi nhánh?


2
À, về cơ bản đây là tùy chọn B được mô tả bởi @ Mark-Longair ở trên
Tim

2

Đây là một cách đơn giản hơn nhiều:

  1. Tạo một chi nhánh mới

  2. Trên chi nhánh mới của bạn thực hiện một git merge master- điều này sẽ hợp nhất các thay đổi đã cam kết (không được đẩy) của bạn với chi nhánh mới của bạn

  3. Xóa chi nhánh chính của bạn git branch -D mastersử dụng -Dthay -dvì vì bạn muốn xóa chi nhánh.

  4. Chỉ cần thực hiện git fetchtrên nhánh chính của bạn và thực hiện git pulltrên nhánh chính của bạn để đảm bảo bạn có mã mới nhất cho nhóm của mình.


1

Một cách tiếp cận đơn giản hơn, mà tôi đã và đang sử dụng (giả sử bạn muốn di chuyển 4 lần xác nhận):

git format-patch HEAD~4

(Xem trong thư mục mà bạn đã thực hiện lệnh cuối cùng cho 4 .patchtệp)

git reset HEAD~4 --hard

git checkout -b tmp/my-new-branch

Sau đó:

git apply /path/to/patch.patch

Theo thứ tự bạn muốn.


0
  1. Kiểm tra bản sao mới của các nguồn của bạn

    git clone ........

  2. Tạo chi nhánh từ vị trí mong muốn

    git checkout {position} git checkout -b {branch-name}

  3. Thêm kho lưu trữ từ xa

    git remote add shared ../{original sources location}.git

  4. Lấy nguồn từ xa

    git fetch shared

  5. Thanh toán chi nhánh mong muốn

    git checkout {branch-name}

  6. Hợp nhất các nguồn

    git merge shared/{original branch from shared repository}


0

Đối với tôi đây là cách tốt nhất:

  1. Kiểm tra các thay đổi và hợp nhất xung đột git fetch
  2. Tạo một nhánh mới git branch my-changesvà đẩy đến từ xa
  3. Thay đổi ngược dòng sang nhánh mới được tạo git master -u upstream-branch remotes/origin/my-changes
  4. Đẩy các cam kết của bạn đến chi nhánh thượng nguồn mới.
  5. Chuyển về thượng nguồn trước git branch master --set-upstream-to remotes/origin/master
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.