Làm cách nào để sửa một cây con git sau khi lực lượng dự án ngược dòng đẩy lên chủ?


13

Tôi đã thử nghiệm sử dụng cây con git và đã gặp phải tình huống sau.

Tôi đã sử dụng git Subree để thêm một dự án bên ngoài vào repo của mình, tôi cố tình giữ tất cả lịch sử cho dự án ngược dòng vì tôi muốn có thể tham khảo lịch sử của dự án và cũng đóng góp lại cho dự án ngược dòng sau này.

Hóa ra, một người đóng góp khác cho dự án ngược dòng đã vô tình đẩy một tệp lớn vào nhánh chính. Để khắc phục điều này, dự án ngược dòng viết lại lịch sử và lực đẩy lên chủ. Khi tạo "monorepo" của mình, tôi đã bao gồm cam kết này và tôi cũng muốn xóa nó.

Làm cách nào tôi có thể cập nhật kho lưu trữ của mình để phản ánh lịch sử mới của cây con?

Nỗ lực đầu tiên của tôi là sử dụng nhánh lọc để loại bỏ hoàn toàn cây con và tất cả lịch sử.

git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch upstream-project-dir' --prune-empty HEAD

Khi phiên bản cũ của cây con đã bị xóa, tôi có thể thêm lại cây con bằng cách sử dụng tổng thể ngược dòng mới. Tuy nhiên, điều này không hoạt động vì một số lý do, lịch sử cam kết vẫn hiển thị trong đầu ra nhật ký git.

Cập nhật

Tôi đã viết lên các bước để tạo một ví dụ có thể tái tạo tối thiểu.

  1. Đầu tiên tạo một repo git trống.

    git init test-monorepo
    cd ./test-monorepo
    
  2. Tạo một cam kết ban đầu.

    echo hello world > README
    git add README
    git commit -m 'initial commit'
    
  3. Bây giờ thêm một cây con cho một dự án bên ngoài.

    git remote add thirdparty git@github.com:teivah/algodeck.git
    git fetch thirdparty
    git subtree add --prefix algodeck thirdparty master
    
  4. Thực hiện một số cam kết trên monorepo

    echo dont panic >> algodeck/README.md
    git commit -a -m 'test commit'
    
  5. Bây giờ hãy thử sử dụng nhánh lọc git để loại bỏ cây con.

    git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch algodeck' --prune-empty HEAD
    
  6. Kiểm tra đầu ra git log, tôi hy vọng sẽ chỉ thấy cam kết ban đầu của tôi.

    git log
    

Bạn đã thử git gc --prune = ngay bây giờ để loại bỏ các cam kết cũ chưa? Có một số giới thiệu cho các cam kết phiên bản cũ?
Damiano

1
Tôi chưa thử điều này, nhưng sẽ không git gc --prune=nowxóa các cam kết không xuất hiện trong git log?
csnate

sử dụng nhánh git -all (mà tôi cho rằng bạn đang sử dụng để xem các cam kết "cũ") cũng sẽ hiển thị các cam kết không liên quan đến chi nhánh hiện tại của bạn.
Damiano

1
Thật ra, tôi chỉ đang làm git log, không tranh luận và tôi vẫn thấy những cam kết cũ.
csnate

Xin vui lòng bạn có thể đăng nhật ký git của bạn --pretty --all --graph? Chỉ cần hiểu tình hình của bạn
Damiano

Câu trả lời:


0

bạn đã có những cam kết xấu trong lịch sử của mình và bạn cần phải thoát khỏi nó trước khi tiếp tục

giả sử bạn đã masterchuyển hướng lần cuối và không thể làm gì khác (tôi thực sự không có chi nhánh của bạn trong tầm mắt, vì vậy tôi cần phải giả định điều gì đó để bắt đầu)

bạn có thể kiểm tra cam kết trước đó và đẩy điểm đánh dấu chi nhánh của bạn lùi lại 1 bước (hoặc lùi lại X) sẽ vô hại trong mọi trường hợp và sau đó kéo lại

ví dụ

git checkout master~1
git branch master -f
git checkout master
git pull
  1. git checkout master~1 để kiểm tra cam kết của cha mẹ, git cảnh báo chúng tôi không có chi nhánh
  2. git branch master -f để buộc thanh toán hiện tại trở thành chủ một lần nữa, nghĩa là nó thực sự tua lại nhánh chính với cam kết trước đó (hoặc cam kết trước đó) và từ đây, không quan trọng là ngược dòng có bắt buộc hay không, chúng ta có thể tiếp tục bình thường hoặc thậm chí quay trở lại bước trên nếu cần, chúng tôi chỉ có thể kéo lại chủ, mà không mất bất cứ thứ gì từ thượng nguồn (điều này đối với chúng tôi có thể chỉ đọc, chúng tôi sẽ không thúc đẩy bất cứ điều gì cho việc này)
  3. git checkout master để ở trên nhánh chính "tua lại" của chúng tôi, cùng một cam kết mà chúng tôi đang thực hiện, nhưng bây giờ thay vào đó là trên nhánh
  4. git pullđể kéo lại chủ (có thể có hoặc không --prune), nếu ngược dòng, chúng ta sẽ quay lại theo dõi từ đây, nếu không, chúng ta sẽ nhận được cùng một thứ, nếu chúng ta giống nhau và không được cho là, có lẽ chúng ta cần quay lại bước 1 ở trên và tua lại nhiều lần xác nhận hơn, ví dụ git checkout master~5hoặc bất cứ điều gì (khi cần)

Tôi không nghĩ rằng nó sẽ hoạt động vớigit subtree
csnate

@csnate có thể kiểm tra các cam kết trước đó từ một subrepo và làm theo quy trình rất giống nhau, nếu bạn xây dựng MCVE, sẽ dễ dàng hơn để cho bạn biết các lệnh chính xác để thực hiện theo stackoverflow.com/help/minimal-reproducible-example
arhak

Tôi sẽ cố gắng tạo một repo mẫu trên GitHub.
csnate

Tôi đã tạo một tập hợp các bước trong câu hỏi ban đầu cho thấy vấn đề.
csnate

0
  1. trên repo của bạn, dọn sạch lịch sử cam kết cho điều khiển từ xa này:

    git fetch upstream
    
  2. nếu một trong các cam kết của riêng bạn có một cam kết bao gồm tệp lớn, hãy viết lại lịch sử của bạn để tệp lớn này không còn được tham chiếu

    # using one or more of the following commands :
    git rebase --interactive
    git filter-branch
    ...
    

Với hai bước này, tệp lớn sẽ không được tham chiếu nữa bởi bất kỳ cam kết nào trong repo của bạn.
Nó cũng sẽ bị xóa khỏi ổ cứng của bạn tại một số thời điểm, khi git chạy trình thu gom rác của nó và sự chậm trễ hết hạn cho các đốm màu lơ lửng đã đạt được.


Nếu bạn có nhu cầu khẩn cấp để xóa tệp lớn này càng sớm càng tốt khỏi ổ cứng của bạn:

Chạy thủ công

git gc --prune=now
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.