“Git pull” có thể tự động lưu trữ và bật các thay đổi đang chờ xử lý không?


122

Tôi biết cách giải quyết vấn đề này:

user@host$ git pull
Updating 9386059..6e3ffde
error: Your local changes to the following files would be overwritten by merge:
    foo.bar
Please, commit your changes or stash them before you can merge.
Aborting

Nhưng không có cách nào để git pulllàm stashpopnhảy cho tôi?

Nếu lệnh này có tên khác, không sao cả.

Tạo bí danh shell cho git stash; git pull; git stash poplà một giải pháp, nhưng tôi tìm kiếm một giải pháp tốt hơn.


những gì về một bí danh git ?
Яois

20
Chạy theo git stash; git pull; git stash popchương trình rất nguy hiểm, bởi vì nếu không có gì để lưu trữ, git stashsẽ là không chọn, nhưng git stash popsẽ bật ra kho lưu trữ cuối cùng (nếu có), gần như chắc chắn không phải là những gì bạn muốn. Người dùng xé có một bài đăng tuyệt vời về điều này trên Stack Overflow, nhưng tôi không thể tìm thấy nó ...
joong0bs


1
@guettli Tôi không ám chỉ câu hỏi của bạn là trùng lặp, tôi chỉ đang trả lời bình luận của Jubobs.
VonC

2
Ở một bước xa hơn, hoạt động sẽ chỉ thành công nếu vật chứa có thể được áp dụng sạch sẽ sau khi kéo. Nếu có xung đột, thì toàn bộ hoạt động không thành công nguyên tử để cây không bị thay đổi. Đây là những gì tôi muốn làm: kéo xuống các thay đổi với các thay đổi cục bộ của tôi được hợp nhất hoặc nếu không sẽ xảy ra lỗi và để tôi tự quyết định việc cần làm tiếp theo theo cách thủ công. Loại 'giao dịch git' này có khả thi không?
Ed Avis

Câu trả lời:


185

Đối với Git 2.6+ (phát hành ngày 28 tháng 9 năm 2015)

Các chỉ có git config cài đặt sẽ được quan tâm là:

rebase.autoStash

(với Git 2.27, quý 2 năm 2020, bây giờ bạn cũng có merge.autostash, xem bên dưới)

Khi được đặt thành true, tự động tạo kho lưu trữ tạm thời trước khi hoạt động bắt đầu và áp dụng sau khi hoạt động kết thúc.
Điều này có nghĩa là bạn có thể chạy rebase trên một worktree bẩn.

Tuy nhiên, hãy sử dụng cẩn thận: ứng dụng lưu trữ cuối cùng sau khi rebase thành công có thể dẫn đến xung đột không nhỏ. Giá trị mặc định là false.

kết hợp điều đó với:

pull.rebase

Khi đúng, hãy căn cứ lại các nhánh trên đầu nhánh đã tìm nạp, thay vì hợp nhất nhánh mặc định từ điều khiển từ xa mặc định khi chạy "git pull".

git config pull.rebase true
git config rebase.autoStash true

Như vậy là đủ cho một git pullcông việc đơn giản ngay cả trong một cái cây bẩn thỉu.
Không cần bí danh trong trường hợp đó.


Xem cam kết 53c76dc (04 tháng 7 năm 2015) bởi Kevin Daudt ( Ikke) .
(Hợp nhất bởi Junio ​​C Hamano - gitster- in cam kết e69b408 , ngày 17 tháng 8 năm 2015)

pull: cho phép cây bẩn khi rebase.autostashđược bật

rebase đã học cách lưu trữ các thay đổi khi nó gặp một cây công việc bẩn thỉu, nhưng git pull --rebasekhông.

Chỉ xác minh xem cây làm việc có bị bẩn khi rebase.autostashkhông được kích hoạt hay không.


Lưu ý: nếu bạn muốn kéo mà không có autostash (mặc dù đã rebase.autoStash trueđược thiết lập), bạn có từ git 2.9 (tháng 6 năm 2016):

 pull --rebase --no-autostash

Xem cam kết 450dd1d , cam kết 1662297 , cam kết 44a59ff , cam kết 5c82bcd , cam kết 6ddc97c , cam kết eff960b , cam kết efa195d (02/04/2016) và cam kết f66398e , cam kết c48d73b (21/03/2016) bởi Mehul Jain ( mehul2029) .
(Hợp nhất bởi Junio ​​C Hamano - gitster- trong cam kết 7c137bb , ngày 13 tháng 4 năm 2016)

Cam kết f66398e nói riêng bao gồm:

pull --rebase: thêm --[no-]autostashcờ

Nếu rebase.autoStashbiến cấu hình được đặt, không có cách nào để ghi đè nó cho " git pull --rebase" từ dòng lệnh.

Dạy " git pull --rebase" --[no-]autostashcờ dòng lệnh ghi đè giá trị hiện tại của rebase.autoStash, nếu được đặt. Vì " git rebase" hiểu --[no-]autostashtùy chọn, chỉ là vấn đề chuyển tùy chọn cho " git rebase" khi " git pull --rebase" được gọi.


Cảnh báo: trước Git 2.14 (Quý 3 năm 2017), " git pull --rebase --autostash" không tự động lưu trữ khi lịch sử cục bộ tua nhanh về phía ngược dòng.

Xem cam kết f15e7cf (01/06/2017) của Tyler Brazier ( tylerbrazier) .
(Merged bởi Junio C Hamano - gitster- trong phạm 35898ea , 05 Tháng 6 2017)

pull: ff --rebase --autostashhoạt động trong repo bẩn

Khi git pull --rebase --autostashở trong một kho lưu trữ bẩn dẫn đến tua đi nhanh, không có gì đang được tự động rửa và kéo không thành công.
Điều này là do một phím tắt để tránh chạy rebase khi chúng ta có thể tua đi nhanh, nhưng tự động viết tắt bị bỏ qua trên đường dẫn đó.


Cập nhật: Mariusz Pawelski hỏi trong phần bình luận một câu hỏi thú vị:

Vì vậy, mọi người đang viết về autostashthời điểm bạn thực hiện rebase (hoặc pull --rebase).

Nhưng không ai quan tâm đến việc tự động sửa lỗi khi bạn thực hiện thao tác kéo bình thường với hợp nhất .
Vì vậy, không có công tắc tự động cho điều đó? Hoặc tôi đang thiếu một cái gì đó? Tôi thích làm hơn git pull --rebasenhưng OP đã hỏi về kéo git " tiêu chuẩn "

Câu trả lời:

Các chủ đề ban đầu thảo luận về tính năng autostash này, nó đã được thực hiện ban đầu cho cả git pull(merge) và git pull --rebase.

Nhưng ... Junio ​​C Hamano (người bảo trì Git) lưu ý rằng:

pull-mergeTheo định nghĩa, nếu đó là thứ gì đó gây ra "sự khó chịu" đã kích hoạt chủ đề này, thì thay đổi cục bộ sẽ chồng chéo với hợp nhất và "cửa sổ bật lên" nội bộ này sẽ chạm vào các đường dẫn mà hợp nhất đã chạm vào và nó có khả năng không dẫn đến "Đã bỏ "nhưng để lại những mâu thuẫn tiếp theo sẽ được giải quyết.

Tôi nghi ngờ rằng pull.autostashcấu hình không phải là một bổ sung tốt vì nó khuyến khích một quy trình làm việc tồi tệ, khó chịu.
Trong những trường hợp đơn giản, nó có thể không ảnh hưởng gì, nhưng khi những thay đổi cục bộ phức tạp, nó sẽ ảnh hưởng tích cực hơn là không có nó và cấu hình cướp đi động cơ để lựa chọn.

Phương trình hơi khác đối với "pull-rebase", vì "rebase" yêu cầu bạn bắt đầu từ một cây làm việc sạch, vì vậy "tải xuống rồi dừng lại" cảm thấy phiền toái lớn hơn. Tôi nghi ngờ rằng việc nới lỏng đó có thể là một giải pháp hiệu quả hơn cho vấn đề thực sự.

Vì vậy, liên quan đến pull-merge cổ điển, tốt hơn là:

khuyến khích người dùng suy nghĩ về bản chất của WIP mà họ có trong cây làm việc trước khi chạy " git pull" .
Đó có phải là một con quái vật quá phức tạp có thể can thiệp vào những gì người khác đang làm, hay đó là một thay đổi nhỏ mà anh ta có thể giấu đi và bật lại?

Nếu trước đây, anh ta sẽ làm tốt hơn rất nhiều khi làm " checkout -b", hãy tiếp tục làm việc cho đến khi sự thay đổi cục bộ trở nên tốt hơn và "cam kết", trước khi kéo vào nhánh ban đầu.

Nếu sau này, anh ta nên làm:

  • " git pull",
  • sau khi tìm thấy nó xung đột, hãy chạy
    • git stash,
    • git merge FETCH_HEAD
    • git stash pop

Điều đó đang được nói, với Git 2.27 (Quý 2 năm 2020), " git pull" đã học cách cảnh báo khi không có pull.rebasecấu hình nào tồn tại và --[no-]rebasecũng không --ff-onlyđược đưa ra (điều này sẽ dẫn đến hợp nhất).

Xem cam kết d18c950 (10 tháng 3 năm 2020) của Alex Henrie ( alexhenrie) .
(Được hợp nhất bởi Junio ​​C Hamano - gitster- trong cam kết 1c56d6f , ngày 27 tháng 3 năm 2020)

pull: cảnh báo nếu người dùng không nói nên căn cứ lại hay hợp nhất

Người ký tên: Alex Henrie

Thường người dùng Git mới làm quen quên nói " pull --rebase" và kết thúc bằng một hợp nhất không cần thiết từ ngược dòng.

Những gì họ thường muốn là " pull --rebase" trong các trường hợp đơn giản hơn hoặc " pull --ff-only" để cập nhật bản sao của các nhánh tích hợp chính và căn cứ lại công việc của họ một cách riêng biệt.
Biến pull.rebasecấu hình tồn tại để giúp họ trong những trường hợp đơn giản hơn, nhưng không có cơ chế nào để khiến những người dùng này biết về nó.

Đưa ra thông báo cảnh báo khi không có --[no-]rebasetùy chọn nào từ dòng lệnh và không có pull.rebasebiến cấu hình nào được đưa ra.
Điều này sẽ gây bất tiện cho những người không bao giờ muốn " pull --rebase", những người không phải làm bất cứ điều gì đặc biệt, nhưng chi phí của sự bất tiện này chỉ được trả một lần cho mỗi người dùng, đây phải là chi phí hợp lý để giúp một số người dùng mới.


Với Git 2.27 (Quý 2 năm 2020), " git merge" tìm hiểu --autostashtùy chọn "" và merge.autostashcài đặt mới .

Xem cam kết d9f15d3 , cam kết f8a1785 , cam kết a03b555 , cam kết 804fe31 , cam kết 12b6e13 , cam kết 0dd562e , cam kết 0816f1d , cam kết 9bb3dea , cam kết 4d4bc15 , cam kết b309a97 , cam kết f213f06 , cam kết 86ed00a , cam kết facca7f , cam kết be1bb60 , cam kết efcf6cf , cam kết c20de8b , cam kết bfa50c2 , cam kết 3442c3d , cam kết 5b2f6d9 (07 tháng 4 năm 2020), cam kết 65c425a( 04/04/2020 ) và commit fd6852c , commit 805d9ea (21/03/2020) bởi Denton Liu ( Denton-L) .
(Được hợp nhất bởi Junio ​​C Hamano - gitster- in commit bf10200 , 29/04/2020)

pull: pass --autostash để hợp nhất

Ký tên: Denton Liu

Trước đây, --autostashchỉ làm việc với git pull --rebase.

Tuy nhiên, trong bản vá cuối cùng, hợp nhất cũng đã học được --autostashvì vậy không có lý do gì chúng ta nên có hạn chế này nữa.
Dạy kéo để vượt qua --autostashđể hợp nhất, giống như nó đã làm cho rebase.

Và:

rebase: sử dụng apply_autostash()từ sequencer.c

Ký tên: Denton Liu

Các apply_autostash()chức năng trong builtin/rebase.clà đủ tương tự như apply_autostash()chức năng trong sequencer.cđó họ hầu như hoán đổi cho nhau, ngoại trừ cho các loại arg họ chấp nhận. Tạo sequencer.cphiên bản cũ và sử dụng nó trong rebase.

Phiên bản rebase đã được giới thiệu trong 6defce2b02 ("nội trang rebase: --autostashtùy chọn hỗ trợ ", 2018-09-04, Git v2.20.0-rc0 - hợp nhất được liệt kê trong lô # 8 ) như một phần của chuyển đổi shell sang C.
Nó đã chọn sao chép chức năng bởi vì, vào thời điểm đó, có một dự án đang tiến hành khác cũng đang chuyển đổi rebase tương tác từ shell sang C và họ không muốn đụng độ với chúng bằng cách tái cấu trúc sequencer.cphiên bản của apply_autostash().
Vì nỗ lực của cả hai đã được thực hiện từ lâu, nên bây giờ chúng tôi có thể thoải mái kết hợp chúng với nhau.


Kể từ 2.4.2, điều này vẫn chưa được thực hiện. Có lẽ một ngày nào đó. rebase.autoStashchỉ áp dụng khi sử dụng rebase. pull.rebasechỉ áp dụng khi sử dụng kéo.
Randal Schwartz

"Như vậy là đủ để một cú kéo git đơn giản hoạt động ngay cả trong một cái cây bẩn thỉu." Như Randal đã nhận xét, điều này vẫn chưa đúng. Pull.c chủ hiện tại vẫn chọn die_on_unclean_work_tree.
Pradhan

1
@Pradhan Tôi đồng ý. Việc triển khai vừa được hoàn thiện vào sáng nay và sẽ được lên git 2.6. Tôi đã chỉnh sửa câu trả lời để làm rõ điều đó.
VonC

Tôi đã xác nhận rằng autostash đang hoạt động với git 2.5.5.
Joshua Hoblitt 29/12/16

1
Vì vậy, mọi người đang viết về autostash khi bạn làm rebase(hoặc pull --rebase). Nhưng không ai quan tâm đến việc tự động rửa khi bạn làm bình thường pullvới các hợp nhất. Vì vậy, không có công tắc tự động cho điều đó? Hoặc tôi đang thiếu một cái gì đó? Tôi thích làm hơn git pull --rebasenhưng OP đã hỏi về "tiêu chuẩn"git pull
Mariusz Pawelski.

41

Để tiết kiệm vài giây cho những người khám phá sắp tới, đây là bản tóm tắt (cảm ơn @VonC):

git pull --rebase --autostash

6
Vấn đề là: sau một git config pull.rebase truegit config rebase.autoStash true, tất cả những gì bạn cần là git pull. Chỉ là git pull. Không cần tùy chọn khác.
VonC

3
Có vẻ như bạn cần ít nhất Git 2.9 cho --autostashtùy chọn. Các -c rebase.autoStash=truehoạt động trong Git 2.6 trở đi.
ntc2 17/02/17

15

Như nhận xét ở trên đã nêu, việc đặt hai giá trị cấu hình hiện không hoạt động git pull, vì cấu hình autostash chỉ áp dụng cho các lần phục hồi thực tế. Các lệnh git này thực hiện những gì bạn muốn:

git fetch
git rebase --autostash FETCH_HEAD

Hoặc đặt nó làm bí danh:

git config alias.pullr '!git fetch; git rebase --autostash FETCH_HEAD'

Sau đó làm:

git pullr

Tất nhiên, bí danh này có thể được đổi tên theo ý muốn.


7

Với Git 2.6+, bạn có thể sử dụng như sau:

alias gup='git -c rebase.autoStash=true pull --rebase'

Điều này --rebaselàm cho việc sử dụng git-pull rebasethay vì sử dụng merge, vì vậy các cài đặt / tùy chọn như --ff-onlysẽ không áp dụng.

Tôi đang sử dụng bí danh để kéo --ff-onlytheo mặc định ( git pull --ff-only) và sau đó có thể sử dụng gup(từ phía trên) trong trường hợp không thể hợp nhất tua đi nhanh hoặc có các thay đổi được lưu trữ.


Sự khác biệt chính giữa git pull --ff-onlygit pull pull --rebase --autostash
alper

0

Như bạn đã đề cập, đây là cách để làm điều đó. Bạn có thể sử dụng nó trong bí danh để tiết kiệm khi nhập và sử dụng phím tắt hoặc bạn có thể sử dụng nó trong một dòng duy nhất (cũng có thể là bí danh)

git stash && git pull --rebase && git stash pop

Nó sẽ làm điều tương tự như bạn đã làm nhưng trong một dòng duy nhất (&&) và bạn được đặt làm bí danh, nó thậm chí sẽ ngắn hơn.

Các dòng sau sẽ hiển thị các thay đổi đến / đi trước khi bạn kéo / đẩy

git log ^master origin/master
git log master ^origin/master

8
Cách tiếp cận này không an toàn: nếu không có gì để lưu trữ, lệnh đầu tiên sẽ không làm gì cả, và sau đó stash popsẽ loại bỏ một số nội dung ngẫu nhiên từ trước đó.
John Zwinck

Chỉ cần nói rõ thêm: ngay cả khi git stashkhông lưu trữ bất kỳ thứ gì, nó vẫn "trả về" không có mã lỗi, do đó && sẽ vẫn tiếp tục với git pullgit stash popvà bật một kho lưu trữ trước đó. Vì vậy, tốt hơn là không sử dụng nó trừ khi bạn rất chắc chắn rằng nó sẽ lưu trữ một cái gì đó!
MoonLite
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.