Việc xóa một nhánh trong git sẽ loại bỏ nó khỏi lịch sử?


189

Đến từ svn, mới bắt đầu làm quen với git.

Khi một nhánh bị xóa trong git, nó có bị xóa khỏi lịch sử không?

Trong svn, bạn có thể dễ dàng khôi phục một nhánh bằng cách hoàn nguyên thao tác xóa (hợp nhất ngược). Giống như tất cả các xóa trong svn, nhánh không bao giờ thực sự bị xóa, nó chỉ bị xóa khỏi cây hiện tại.

Nếu nhánh thực sự bị xóa khỏi lịch sử trong git, điều gì xảy ra với những thay đổi được hợp nhất từ ​​nhánh đó? Họ có được giữ lại không?

Câu trả lời:


249

Chi nhánh chỉ là con trỏ để cam kết trong git. Trong git, mỗi cam kết có một cây nguồn hoàn chỉnh, nó là một cấu trúc rất khác với svn nơi tất cả các nhánh và thẻ (theo quy ước) sống trong các 'thư mục' riêng biệt của kho lưu trữ cùng với 'thân cây' đặc biệt.

Nếu nhánh được sáp nhập vào một nhánh khác trước khi nó bị xóa thì tất cả các cam kết sẽ vẫn có thể truy cập được từ nhánh khác khi nhánh đầu tiên bị xóa. Họ vẫn chính xác như họ đã từng.

Nếu nhánh bị xóa mà không được sáp nhập vào nhánh khác thì các cam kết trong nhánh đó (cho đến khi điểm rẽ nhánh từ một cam kết vẫn có thể truy cập được) sẽ không còn hiển thị.

Các cam kết vẫn sẽ được giữ lại trong kho lưu trữ và có thể khôi phục chúng ngay sau khi xóa, nhưng cuối cùng chúng sẽ được thu gom rác.


3
Cảm ơn câu trả lời. Bạn có thể làm rõ ý của bạn bằng cách "mỗi cam kết có một cây nguồn hoàn chỉnh" không? Theo tôi hiểu, mỗi cam kết trong git là một tập hợp các deltas liên quan đến cam kết cha mẹ, không phải toàn bộ cây.
Ken Liu

2
@Ken Liu: Một cam kết chứa con trỏ đến 0 hoặc nhiều xác nhận cha mẹ, một đối tượng cây và một số siêu dữ liệu về cam kết. Do đó, cam kết xác định duy nhất cả hai cây nguồn và khi được xem dựa trên (các) cha mẹ của nó, những thay đổi mà nó đã đưa ra.
CB Bailey

9
@Ken Liu: Nó phụ thuộc vào chính xác những gì bạn đã được 'chứa', nhưng vâng, về cơ bản, mỗi cam kết chứa một cây hoàn chỉnh. Trong cơ sở dữ liệu đối tượng, các đối tượng được lập chỉ mục bởi id để các đối tượng được chia sẻ giữa tất cả các đối tượng (cây và cam kết) tham chiếu đến chúng để chi phí lưu trữ ngụ ý không tệ như âm thanh ban đầu. git cũng có một tối ưu hóa lưu trữ hiệu quả (gói tệp) giúp sử dụng không gian đĩa hiệu quả hơn nữa.
CB Bailey

22
"Cuối cùng chúng sẽ được thu gom rác" - Cuối cùng là khi nào?
BadHorsie

7
@BadHorsie, nó phụ thuộc .
AliOli

86

Trong Git, các nhánh chỉ là các con trỏ (tham chiếu) để xác nhận trong một biểu đồ chu kỳ có hướng (DAG) của các xác nhận. Điều này có nghĩa là việc xóa một nhánh chỉ xóa các tham chiếu đến các xác nhận, điều này có thể làm cho một số cam kết trong DAG không thể truy cập được, do đó không thể nhìn thấy. Nhưng tất cả các cam kết trên một nhánh bị xóa vẫn sẽ nằm trong kho lưu trữ, ít nhất là cho đến khi các cam kết không thể truy cập được cắt tỉa (ví dụ: sử dụng git gc).

Lưu ý rằng git branch -dsẽ từ chối xóa một chi nhánh nếu không thể chắc chắn rằng việc xóa nó sẽ không để lại các cam kết không thể truy cập được. Bạn cần sử dụng mạnh hơn git branch -Dđể buộc xóa chi nhánh nếu nó có thể để lại các cam kết không thể truy cập được.

Cũng lưu ý rằng các cam kết không thể truy cập được, nếu chúng có mặt, chỉ là các cam kết giữa đầu cuối của nhánh bị xóa và một cam kết đã được sáp nhập với một nhánh hiện có khác, bất kỳ cam kết được gắn thẻ hoặc điểm phân nhánh; Bất cứ cái nào đến sau. Ví dụ trong tình huống sau:

---- O ---- * ---- * ---- / M ---- * <- chủ <- TRỤ
     \ /
      \ --. ---- .-- / - x --- y <- đã xóa chi nhánh

chỉ cam kết 'x' và 'y' sẽ không thể truy cập được sau khi xóa chi nhánh.

Nếu bạn hoạt động trên một chi nhánh bị xóa trong gc.reflogExpirekhoảng thời gian, mặc định là 90 ngày, bạn sẽ có mẹo cuối cùng của một chi nhánh bị xóa được ghi lại trong phần reflog (xem git reflog show HEAD, hoặc git log --oneline --walk-reflogs HEAD). Bạn sẽ có thể sử dụng reflog CHÍNH để khôi phục con trỏ đã xóa. Cũng lưu ý rằng trong trường hợp này, các cam kết không thể truy cập chỉ trong một nhánh bị xóa sẽ được bảo vệ khỏi việc cắt tỉa (loại bỏ) trong gc.reflogExpireUnreachablekhoảng thời gian, theo mặc định là 30 ngày.

Nếu bạn không thể tìm thấy đầu của một nhánh vừa bị xóa trong reflog cho HEAD, bạn có thể thử sử dụng git fsckđể tìm "cam kết không thể truy cập <sha1>" và kiểm tra các nhánh (thông qua git show <sha1>hoặc git log <sha1>) để tìm đầu của nhánh bị xóa.

Độc lập với cách bạn tìm thấy đầu của một nhánh bị xóa, bạn có thể hoàn tác xóa hoặc thay vào đó tạo lại một nhánh vừa bị xóa bằng cách sử dụng

git branch <deleted-branch> <found-sha1-id>

Tuy nhiên, lưu ý rằng reflog cho một chi nhánh sẽ bị mất.


Ngoài ra còn có tập lệnh git-resurrect.sh trong contrib/đó giúp tìm dấu vết của một đầu nhánh với tên đã cho và hồi sinh (không xóa) nó.


1
Tuyệt vời! git reflog show HEADliệt kê các cam kết và tôi đã tạo ra một chi nhánh mới giống như bạn nói, hoàn hảo.
Steven Almeroth

2

Nếu bạn lo lắng về các nhánh vô tình bị xóa và không còn bản sao repo cục bộ nữa, có các phần mở rộng cho các máy chủ Git doanh nghiệp như Gerrit sẽ phát hiện lịch sử viết lại và xóa chi nhánh, sẽ sao lưu chúng dưới một ref đặc biệt để chúng có thể được khôi phục nếu cần và sẽ không bị cắt xén bởi bộ sưu tập rác. Quản trị viên Gerrit vẫn có thể xóa các cam kết đã chọn nếu cần vì lý do pháp lý.

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.