Git: Quy trình công việc tập trung


Đăng ký nhận thông báo về những video mới nhất
Quy trình công việc Git |  So sánh quy trình công việc

Quy trình công việc Git là một công thức hoặc khuyến nghị về cách sử dụng Git để hoàn thành công việc một cách nhất quán và hiệu quả. Quy trình công việc Git khuyến khích người dùng tận dụng Git hiệu quả và nhất quán. Git cung cấp rất nhiều tính linh hoạt trong cách người dùng quản lý các thay đổi. Do Git tập trung vào tính linh hoạt, không có quy trình chuẩn hóa về cách tương tác với Git. Khi làm việc với một nhóm trong dự án được quản lý Git, điều quan trọng là phải đảm bảo rằng nhóm hoàn toàn đồng ý về cách áp dụng luồng thay đổi. Để đảm bảo nhóm ở cùng một trang, nên xây dựng hoặc chọn quy trình làm việc Git theo thỏa thuận. Có một số quy trình công việc Git công khai có thể phù hợp với nhóm của bạn. Ở đây, chúng ta sẽ thảo luận về một số tùy chọn quy trình công việc này.

Mảng quy trình công việc có thể có thể khiến bạn khó biết phải bắt đầu từ đâu khi triển khai Git tại nơi làm việc. Trang này cung cấp một điểm khởi đầu bằng cách khảo sát các quy trình công việc Git phổ biến nhất cho các nhóm phần mềm.

Khi bạn đọc qua, hãy nhớ rằng các quy trình công việc này được thiết kế theo hướng dẫn chứ không phải là các quy tắc cụ thể. Chúng tôi muốn cho bạn thấy những gì có thể, vì vậy bạn có thể kết hợp và kết hợp các khía cạnh từ các quy trình công việc khác nhau để phù hợp với nhu cầu cá nhân của bạn.

Một quy trình làm việc Git thành công là gì?

Khi đánh giá quy trình làm việc cho nhóm của bạn, điều quan trọng nhất là bạn phải xem xét văn hóa của nhóm. Bạn muốn quy trình làm việc để nâng cao hiệu quả của nhóm của bạn và không phải là gánh nặng làm hạn chế năng suất. Một số điều cần xem xét khi đánh giá quy trình công việc Git là:

  • Liệu quy trình công việc này với quy mô nhóm?
  • Có dễ dàng hoàn tác các lỗi và lỗi với quy trình công việc này không?
  • Liệu quy trình công việc này áp đặt bất kỳ chi phí nhận thức không cần thiết mới nào cho nhóm?

Quy trình làm việc tập trung

quy trình làm việc git |  Kho trung tâm và địa phương

Quy trình công việc tập trung là một quy trình công việc Git tuyệt vời cho các nhóm chuyển từ SVN. Giống như Subversion, Dòng công việc tập trung sử dụng một kho lưu trữ trung tâm để đóng vai trò là điểm truy cập duy nhất cho tất cả các thay đổi đối với dự án. Thay vì trunk, nhánh phát triển mặc định được gọi mastervà tất cả các thay đổi được cam kết vào nhánh này. Quy trình công việc này không yêu cầu bất kỳ chi nhánh nào khác bên cạnh master.

Việc chuyển sang hệ thống kiểm soát phiên bản phân tán có vẻ như là một nhiệm vụ khó khăn, nhưng bạn không phải thay đổi quy trình làm việc hiện tại của mình để tận dụng lợi thế của Git. Nhóm của bạn có thể phát triển các dự án theo cách chính xác giống như họ làm với Subversion.

Tuy nhiên, sử dụng Git để tăng sức mạnh cho quy trình phát triển của bạn mang lại một vài lợi thế so với SVN. Đầu tiên, nó cung cấp cho mọi nhà phát triển bản sao cục bộ của riêng họ cho toàn bộ dự án. Môi trường biệt lập này cho phép mỗi nhà phát triển làm việc độc lập với tất cả các thay đổi khác đối với dự án - họ có thể thêm các cam kết vào kho lưu trữ cục bộ của mình và hoàn toàn quên đi các phát triển ngược dòng cho đến khi thuận tiện cho họ.

Thứ hai, nó cho phép bạn truy cập vào mô hình hợp nhất và phân nhánh mạnh mẽ của Git. Không giống như SVN, các nhánh Git được thiết kế để trở thành một cơ chế không an toàn để tích hợp mã và chia sẻ các thay đổi giữa các kho lưu trữ. Luồng công việc tập trung tương tự như các quy trình công việc khác trong việc sử dụng kho lưu trữ phía máy chủ từ xa mà các nhà phát triển đẩy và kéo biểu mẫu. So với các quy trình công việc khác, Quy trình làm việc tập trung không có yêu cầu kéo hoặc các mẫu thử được xác định. Luồng công việc tập trung thường phù hợp hơn cho các nhóm di chuyển từ SVN sang Git và các nhóm có kích thước nhỏ hơn.

Làm thế nào nó hoạt động

Các nhà phát triển bắt đầu bằng cách nhân bản kho lưu trữ trung tâm. Trong các bản sao cục bộ của dự án, họ chỉnh sửa các tệp và cam kết thay đổi như với SVN; tuy nhiên, các cam kết mới này được lưu trữ cục bộ - chúng hoàn toàn cách ly với kho lưu trữ trung tâm. Điều này cho phép các nhà phát triển trì hoãn việc đồng bộ hóa ngược dòng cho đến khi họ ở điểm dừng thuận tiện.

Để xuất bản các thay đổi cho dự án chính thức, các nhà phát triển "đẩy" masterchi nhánh địa phương của họ đến kho lưu trữ trung tâm. Điều này tương đương với svn commit, ngoại trừ việc nó thêm tất cả các cam kết cục bộ chưa có trong masternhánh trung tâm .

Khởi tạo kho trung tâm

Git Workflow: Khởi tạo kho lưu trữ trung tâm

Đầu tiên, ai đó cần tạo kho lưu trữ trung tâm trên máy chủ. Nếu đó là một dự án mới, bạn có thể khởi tạo một kho lưu trữ trống. Nếu không, bạn sẽ cần nhập kho lưu trữ Git hoặc SVN hiện có.

Các kho lưu trữ trung tâm phải luôn là các kho lưu trữ trần (chúng không nên có một thư mục làm việc), có thể được tạo như sau:

ssh user@host git init --bare /path/to/repo.git

Hãy chắc chắn sử dụng tên người dùng SSH hợp lệ cho user, tên miền hoặc địa chỉ IP của máy chủ của bạn hostvà vị trí bạn muốn lưu trữ repo của mình /path/to/repo.git. Lưu ý rằng .gittiện ích mở rộng thường được gắn vào tên kho lưu trữ để chỉ ra rằng đó là kho lưu trữ trống.

Lưu trữ trung tâm lưu trữ

Các kho lưu trữ trung tâm thường được tạo thông qua các dịch vụ lưu trữ Git của bên thứ 3 như Bitbucket Cloud hoặc Bitbucket Server . Quá trình khởi tạo một kho lưu trữ trần được thảo luận ở trên được xử lý cho bạn bởi dịch vụ lưu trữ. Dịch vụ lưu trữ sau đó sẽ cung cấp một địa chỉ cho kho lưu trữ trung tâm để truy cập từ kho lưu trữ cục bộ của bạn.

Nhân bản kho lưu trữ trung tâm

Tiếp theo, mỗi nhà phát triển tạo một bản sao cục bộ của toàn bộ dự án. Điều này được thực hiện thông qua git clonelệnh:

git clone ssh://user@host/path/to/repo.git

Khi bạn sao chép một kho lưu trữ, Git sẽ tự động thêm một lối tắt được gọi originlại vào kho lưu trữ của cha mẹ mẹ, với giả định rằng bạn sẽ muốn tương tác với nó hơn nữa trên đường. 

Thay đổi và cam kết

Khi kho lưu trữ được sao chép cục bộ, nhà phát triển có thể thực hiện thay đổi bằng cách sử dụng quy trình cam kết Git tiêu chuẩn: chỉnh sửa, giai đoạn và cam kết. Nếu bạn không quen thuộc với khu vực tổ chức, đó là cách để chuẩn bị một cam kết mà không cần phải bao gồm mọi thay đổi trong thư mục làm việc. Điều này cho phép bạn tạo các cam kết tập trung cao độ, ngay cả khi bạn đã thực hiện nhiều thay đổi cục bộ.

git status # View the state of the repo
git add <some-file> # Stage a file
git commit # Commit a file</some-file>

Hãy nhớ rằng vì các lệnh này tạo ra các xác nhận cục bộ, John có thể lặp lại quá trình này bao nhiêu lần tùy ý mà không cần lo lắng về những gì đang diễn ra trong kho lưu trữ trung tâm. Điều này có thể rất hữu ích cho các tính năng lớn cần được chia thành các phần nguyên tử đơn giản hơn.

Đẩy các cam kết mới vào kho lưu trữ trung tâm

Khi kho lưu trữ cục bộ có những thay đổi mới được cam kết. Những thay đổi này sẽ cần được thúc đẩy để chia sẻ với các nhà phát triển khác trong dự án.

git push origin master

Lệnh này sẽ đẩy các thay đổi đã cam kết mới vào kho lưu trữ trung tâm. Khi đẩy các thay đổi vào kho lưu trữ trung tâm, có thể các bản cập nhật từ nhà phát triển khác đã được đẩy trước đó có chứa mã xung đột với các bản cập nhật đẩy dự định. Git sẽ xuất ra một thông báo chỉ ra xung đột này. Trong tình huống này, git pulltrước tiên sẽ cần phải được thực thi. Kịch bản xung đột này sẽ được mở rộng trong phần sau.

Quản lý xung đột

Kho lưu trữ trung tâm đại diện cho dự án chính thức, vì vậy lịch sử cam kết của nó nên được coi là thiêng liêng và bất biến. Nếu các cam kết cục bộ của nhà phát triển chuyển hướng khỏi kho lưu trữ trung tâm, Git sẽ từ chối đẩy các thay đổi của họ vì điều này sẽ ghi đè lên các cam kết chính thức.

Git Workflows: Quản lý xung đột

Trước khi nhà phát triển có thể xuất bản tính năng của họ, họ cần tìm nạp các cam kết trung tâm được cập nhật và khởi động lại các thay đổi của họ trên đầu trang. Điều này giống như nói, tôi muốn thêm các thay đổi của mình vào những gì mọi người đã làm. Kết quả là một lịch sử tuyến tính hoàn hảo, giống như trong quy trình làm việc SVN truyền thống.

Nếu các thay đổi cục bộ xung đột trực tiếp với các cam kết ngược dòng, Git sẽ tạm dừng quá trình khởi động lại và cho bạn cơ hội giải quyết các xung đột theo cách thủ công. Điều thú vị về Git là nó sử dụng giống nhau git statusvà git addcác lệnh cho cả việc tạo các xác nhận và giải quyết xung đột hợp nhất. Điều này giúp các nhà phát triển mới dễ dàng quản lý các hợp nhất của riêng họ. Thêm vào đó, nếu họ gặp rắc rối, Git sẽ dễ dàng hủy bỏ toàn bộ cuộc nổi loạn và thử lại (hoặc đi tìm sự giúp đỡ).

Thí dụ

Hãy lấy một ví dụ chung về cách một nhóm nhỏ điển hình sẽ hợp tác sử dụng quy trình công việc này. Chúng ta sẽ thấy hai nhà phát triển, John và Mary, có thể làm việc trên các tính năng riêng biệt và chia sẻ đóng góp của họ thông qua một kho lưu trữ tập trung.

John làm việc trên tính năng của mình

Quy trình công việc Git: Chỉnh sửa quy trình tính năng Cam kết giai đoạn

Trong kho lưu trữ cục bộ của mình, John có thể phát triển các tính năng bằng cách sử dụng quy trình cam kết Git tiêu chuẩn: chỉnh sửa, giai đoạn và cam kết.

Hãy nhớ rằng vì các lệnh này tạo ra các xác nhận cục bộ, John có thể lặp lại quá trình này bao nhiêu lần tùy ý mà không cần lo lắng về những gì đang diễn ra trong kho lưu trữ trung tâm.

Mary làm việc trên tính năng của mình

Git Workflows: Chỉnh sửa tính năng Cam kết giai đoạn

Trong khi đó, Mary đang làm việc trên tính năng của riêng mình trong kho lưu trữ cục bộ của riêng mình bằng cách sử dụng quy trình chỉnh sửa / giai đoạn / cam kết tương tự. Giống như John, cô ấy không quan tâm đến những gì đang diễn ra trong kho lưu trữ trung tâm và cô ấy thực sự không quan tâm John đang làm gì trong kho lưu trữ cục bộ của mình, vì tất cả các kho lưu trữ cục bộ là riêng tư .

John công bố tính năng của mình

Quy trình làm việc của Git: Xuất bản tính năng

Khi John hoàn thành tính năng của mình, anh ta nên xuất bản các cam kết cục bộ của mình lên kho lưu trữ trung tâm để các thành viên khác trong nhóm có thể truy cập nó. Anh ta có thể làm điều này với git pushlệnh, như vậy:

git push origin master

Hãy nhớ rằng đó originlà kết nối từ xa đến kho lưu trữ trung tâm mà Git đã tạo khi John nhân bản nó. Đối mastersố nói với Git hãy cố gắng làm cho nhánh origincủa nó mastertrông giống như masternhánh của anh ta . Vì kho lưu trữ trung tâm chưa được cập nhật kể từ khi John nhân bản nó, điều này sẽ không dẫn đến bất kỳ xung đột nào và việc đẩy sẽ hoạt động như mong đợi.

Mary cố gắng để xuất bản tính năng của mình

Quy trình công việc Git: Lỗi lệnh đẩy

Chúng ta hãy xem điều gì xảy ra nếu Mary cố gắng thúc đẩy tính năng của mình sau khi John đã xuất bản thành công các thay đổi của mình lên kho lưu trữ trung tâm. Cô ấy có thể sử dụng chính xác lệnh đẩy:

git push origin master

Nhưng, vì lịch sử địa phương của cô đã chuyển hướng khỏi kho lưu trữ trung tâm, Git sẽ từ chối yêu cầu với thông báo lỗi khá dài dòng:

error: failed to push some refs to '/path/to/repo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Điều này ngăn Mary ghi đè lên các cam kết chính thức. Cô ấy cần phải cập nhật các bản cập nhật của John vào kho lưu trữ của mình, tích hợp chúng với các thay đổi cục bộ của mình và sau đó thử lại.

Mary nổi loạn trên đỉnh của John (s)

Quy trình làm việc của Git: Git Pull Rebase

Mary có thể sử dụng git pullđể kết hợp các thay đổi ngược dòng vào kho lưu trữ của mình. Lệnh này giống như kiểu svn updatemàitit kéo toàn bộ lịch sử cam kết ngược dòng vào kho lưu trữ cục bộ của Mary và cố gắng tích hợp nó với các cam kết cục bộ của cô ấy:

git pull --rebase origin master

Các --rebasetùy chọn cho Git để di chuyển tất cả các cam kết của Mary đến chóp của masterchi nhánh sau khi đồng bộ hóa nó với những thay đổi từ kho lưu trữ trung ương, như hình dưới đây:

Quy trình công việc của Git: Rebasing to Master

Kéo vẫn sẽ hoạt động nếu bạn quên tùy chọn này, nhưng bạn sẽ kết thúc với một cam kết hợp nhất không cần thiết, cam kết mỗi khi ai đó cần đồng bộ hóa với kho lưu trữ trung tâm. Đối với quy trình công việc này, tốt hơn hết là nên khởi động lại thay vì tạo một cam kết hợp nhất.

Mary giải quyết một cuộc xung đột hợp nhất

Git Workflows: Rebasing on Commits

Khởi động lại công việc bằng cách chuyển từng cam kết cục bộ sang masterchi nhánh được cập nhật tại một thời điểm. Điều này có nghĩa là bạn nắm bắt được xung đột hợp nhất trên cơ sở cam kết thay vì giải quyết tất cả chúng trong một cam kết hợp nhất lớn. Điều này giữ cho các cam kết của bạn tập trung nhất có thể và làm cho lịch sử dự án sạch sẽ. Đổi lại, điều này làm cho việc tìm ra lỗi được giới thiệu ở đâu dễ dàng hơn và, nếu cần thiết, để đẩy lùi các thay đổi với tác động tối thiểu đến dự án.

Nếu Mary và John đang làm việc trên các tính năng không liên quan, không có khả năng quá trình nổi loạn sẽ tạo ra xung đột. Nhưng nếu có, Git sẽ tạm dừng rebase tại cam kết hiện tại và xuất thông báo sau, cùng với một số hướng dẫn liên quan:

CONFLICT (content): Merge conflict in <some-file>
Quy trình công việc Git: Giải quyết xung đột

Điều tuyệt vời về Git là bất cứ ai cũng có thể giải quyết xung đột hợp nhất của riêng họ. Trong ví dụ của chúng tôi, Mary chỉ đơn giản là chạy một git statusđể xem vấn đề ở đâu. Các tệp bị xung đột sẽ xuất hiện trong phần Đường dẫn không được trộn:

# Unmerged paths:
# (use "git reset HEAD <some-file>..." to unstage)
# (use "git add/rm <some-file>..." as appropriate to mark resolution)
#
# both modified: <some-file>

Sau đó, cô ấy sẽ chỉnh sửa (các) tệp theo ý thích của mình. Khi cô ấy hài lòng với kết quả, cô ấy có thể tạo (các) tệp theo cách thông thường và git rebaselàm phần còn lại:

git add <some-file>
git rebase --continue

Và đó là tất cả để có nó. Git sẽ chuyển sang cam kết tiếp theo và lặp lại quy trình cho bất kỳ cam kết nào khác tạo ra xung đột.

Nếu bạn đi đến điểm này và nhận ra và bạn không biết chuyện gì đang xảy ra, đừng hoảng sợ. Chỉ cần thực hiện lệnh sau và bạn sẽ quay lại ngay nơi bạn bắt đầu:

git rebase --abort

Mary xuất bản thành công tính năng của mình

Git Workflows: Đồng bộ hóa Repo trung tâm

Sau khi cô ấy hoàn thành đồng bộ hóa với kho lưu trữ trung tâm, Mary sẽ có thể xuất bản các thay đổi của mình thành công:

git push origin master

Đi đâu từ đây

Như bạn có thể thấy, có thể sao chép môi trường phát triển Subversion truyền thống chỉ bằng một số lệnh Git. Điều này rất tốt cho việc chuyển các nhóm ra khỏi SVN, nhưng nó không thúc đẩy bản chất phân tán của Git.

Quy trình làm việc tập trung là tuyệt vời cho các nhóm nhỏ. Quá trình giải quyết xung đột chi tiết ở trên có thể tạo ra một nút cổ chai khi nhóm của bạn có quy mô. Nếu nhóm của bạn cảm thấy thoải mái với Quy trình làm việc tập trung nhưng muốn hợp lý hóa các nỗ lực hợp tác của mình, thì chắc chắn đáng để khám phá lợi ích của Quy trình chi nhánh tính năng . Bằng cách dành một nhánh riêng biệt cho từng tính năng, có thể bắt đầu các cuộc thảo luận chuyên sâu xung quanh các bổ sung mới trước khi tích hợp chúng vào dự án chính thức.

Quy trình công việc phổ biến khác

Luồng công việc tập trung về cơ bản là một khối xây dựng cho các quy trình công việc Git khác. Các quy trình công việc Git phổ biến nhất sẽ có một số loại repo tập trung mà các nhà phát triển riêng lẻ sẽ đẩy và kéo từ đó. Dưới đây chúng tôi sẽ thảo luận ngắn gọn về một số quy trình công việc Git phổ biến khác. Các quy trình công việc mở rộng này cung cấp các mẫu chuyên biệt hơn liên quan đến việc quản lý các chi nhánh để phát triển tính năng, sửa lỗi nóng và phát hành cuối cùng.

Phân nhánh tính năng

Phân nhánh tính năng là một phần mở rộng hợp lý của Quy trình làm việc tập trung. Ý tưởng cốt lõi đằng sau quy trình Chi nhánh tính năng là tất cả sự phát triển tính năng nên diễn ra trong một nhánh dành riêng thay vì masterchi nhánh. Việc đóng gói này giúp nhiều nhà phát triển dễ dàng làm việc trên một tính năng cụ thể mà không làm ảnh hưởng đến cơ sở mã chính. Điều đó cũng có nghĩa là masterchi nhánh không bao giờ chứa mã bị hỏng, đó là một lợi thế rất lớn cho môi trường tích hợp liên tục. 

Quy trình làm việc của Gitflow

Dòng công việc Gitflow được xuất bản lần đầu tiên trong một bài đăng trên blog được đánh giá cao năm 2010 từ  Vincent Driessen tại nvie . Luồng công việc Gitflow định nghĩa một mô hình phân nhánh nghiêm ngặt được thiết kế xung quanh bản phát hành dự án. Quy trình công việc này không thêm bất kỳ khái niệm hoặc lệnh mới nào ngoài những gì cần thiết cho Quy trình chi nhánh tính năng. Thay vào đó, nó gán các vai trò rất cụ thể cho các nhánh khác nhau và xác định cách thức và thời điểm chúng nên tương tác. 

Quy trình làm việc

Các forking Workflow về cơ bản là khác nhau hơn so với quy trình công việc khác được thảo luận trong hướng dẫn này. Thay vì sử dụng một kho lưu trữ phía máy chủ duy nhất để hoạt động như cơ sở mã cơ sở trung tâm, nó cung cấp cho mọi nhà phát triển một kho lưu trữ phía máy chủ. Điều này có nghĩa là mỗi người đóng góp không chỉ có một, mà là hai kho Git: một kho riêng cục bộ và một bên máy chủ công cộng. 

Hướng dẫn

Không có một kích thước phù hợp với tất cả quy trình làm việc của Git. Như đã nói trước đây, điều quan trọng là phát triển quy trình công việc Git, đó là nâng cao năng suất cho nhóm của bạn. Ngoài văn hóa nhóm, một quy trình làm việc cũng nên bổ sung cho văn hóa kinh doanh. Các tính năng Git như chi nhánh và thẻ sẽ bổ sung cho lịch phát hành của doanh nghiệp của bạn. Nếu nhóm của bạn đang sử dụng  phần mềm quản lý dự án theo dõi nhiệm vụ,  bạn có thể muốn sử dụng các nhánh tương ứng với các nhiệm vụ đang diễn ra. Ngoài ra, một số hướng dẫn cần xem xét khi quyết định quy trình làm việc là:

Cành ngắn

Càng sống lâu, tách khỏi nhánh sản xuất, nguy cơ xung đột và thách thức triển khai càng cao. Các chi nhánh ngắn hạn thúc đẩy sáp nhập và triển khai sạch hơn.

Giảm thiểu và đơn giản hóa hoàn nguyên

Điều quan trọng là có một quy trình công việc giúp chủ động ngăn chặn các sự hợp nhất sẽ phải được hoàn nguyên. Một quy trình làm việc kiểm tra một nhánh trước khi cho phép nó được sáp nhập vào masternhánh là một ví dụ. Tuy nhiên, tai nạn xảy ra. Điều đó đang được nói, thật có lợi khi có một quy trình làm việc cho phép hoàn nguyên dễ dàng mà không làm gián đoạn dòng chảy cho các thành viên khác trong nhóm.

Phù hợp với lịch phát hành

Một quy trình công việc sẽ bổ sung cho chu kỳ phát hành phát triển phần mềm của doanh nghiệp bạn. Nếu bạn có kế hoạch phát hành nhiều lần trong ngày, bạn sẽ muốn giữ cho masterchi nhánh của mình ổn định. Nếu lịch phát hành của bạn ít thường xuyên hơn, bạn có thể muốn xem xét sử dụng thẻ Git để gắn thẻ một nhánh vào phiên bản.

Tóm lược

Trong tài liệu này, chúng tôi đã thảo luận về quy trình công việc Git. Chúng tôi đã xem xét sâu về Quy trình làm việc tập trung với các ví dụ thực tế. Mở rộng trên Quy trình làm việc tập trung, chúng tôi đã thảo luận về các quy trình công việc chuyên biệt bổ sung. Một số điểm quan trọng trong tài liệu này là:

  • Không có quy trình làm việc Git một kích thước phù hợp với tất cả
  • Một quy trình làm việc nên đơn giản và nâng cao năng suất của nhóm của bạn
  • Yêu cầu kinh doanh của bạn sẽ giúp định hình quy trình công việc Git của bạn

Để đọc về quy trình công việc Git tiếp theo, hãy xem phân tích toàn diện của chúng tôi về  Quy trình chi nhánh tính năng .

Đăng ký nhận thông báo về những video mới nhất
« Prev: Git: Merge Strategies
» Next: Git: Quy trình công việc rẽ nhánh tính năng
Copied !!!