Khám phá các câu hỏi phỏng vấn Git thường gặp, từ cơ bản đến nâng cao, kèm câu trả lời chi tiết, giúp bạn chuẩn bị kỹ lưỡng cho buổi phỏng vấn tiếp theo của mình.
Đọc bài viết này để có thêm thông tin về:
- Các câu hỏi phỏng vấn Git cơ bản (Beginner)
- Các câu hỏi phỏng vấn Git trung cấp (Intermediate)
- Các câu hỏi phỏng vấn Git nâng cao (Advanced)
Tổng quan về Git
Git là gì?
Git là một hệ thống quản lý phiên bản phân tán (Distributed Version Control System – DVCS) mạnh mẽ, được ra đời vào năm 2005 bởi Linus Torvalds. Git cung cấp các tính năng để theo dõi lịch sử thay đổi của mã nguồn, phân tách và hợp nhất các nhánh phát triển và quản lý việc lưu trữ mã nguồn.
Điểm nổi bật của Git là cấu trúc phân tán, mỗi người dùng có bản sao đầy đủ của kho lưu trữ, có thể làm việc không cần internet và khả năng quản lý các phiên bản trong mã nguồn dựa vào các bản chụp nhanh (snapshot) thay đổi của tập tin, thay vì lưu trữ lại sự khác biệt như các hệ thống khác.
Đọc thêm: Git là gì: Định nghĩa, Thuật ngữ cơ bản và Cách cài đặt
Vai trò của Git
Git là một công cụ rất hữu ích trong các dự án phát triển phần mềm, một số chức năng quan trọng phải kể đến là:
- Quản lý phiên bản của mã nguồn: Với khả năng lưu trữ một cách chi tiết các thông tin về những thay đổi xảy ra đối với mã nguồn, Git giúp các lập trình viên trong dự án có thể truy xuất lại lịch sử thay đổi, phát hiện các nguyên nhân khi hệ thống gặp lỗi.
- Nâng cao chất lượng làm việc nhóm: Với tính năng chia nhánh và hợp nhất nhánh, Git giúp giảm thiểu tình trạng xung đột mã nguồn và tiết kiệm thời gian kết hợp mã nguồn.
- Lưu trữ và chia sẻ mã nguồn: Git hỗ trợ kết nối với các kho lưu trữ mã nguồn từ xa như Github, Gitlab, Bitbucket. Điều này giúp bảo vệ mã nguồn an toàn và thuận tiện cho việc chia sẻ giữa các thành viên trong nhóm hoặc chia sẻ ra cộng đồng.
- Phục hồi nhanh chóng: Khi có sự cố xảy ra trong quá trình phát triển tính năng mới, bạn có thể quay trở lại phiên bản trước đó một cách nhanh chóng.
- Hỗ trợ làm việc từ xa: Với Git, bạn có thể làm việc ở bất cứ đâu mà không cần kết nối liên tục với máy chủ. Điều này đặc biệt hữu ích khi làm việc từ xa hoặc trong môi trường không ổn định về mạng.
Các vị trí tuyển dụng yêu cầu kỹ năng về Git
- Lập trình viên phần mềm: Các lập trình viên (Back-end, Front-end, Full stack) là những người trực tiếp tham gia vào quá trình phát triển phần mềm, vì vậy đòi hỏi những vị trí này phải trang bị tốt kiến thức về sử dụng Git.
- Kỹ sư DevOps: Kỹ sư DevOps cần nắm vững kiến thức về Git để dễ dàng triển khai và quản lý các quy trình tự động hóa, tích hợp Git với các công cụ CI/CD như Jenkins, GitHub Actions, GitLab CI.
- Quản lý dự án: Vị trí này cần có kiến thức về Git để có thể theo dõi được quá trình làm việc của cách thành viên thông qua Pull Request hay lịch sử thay đổi của mã nguồn. Ngoài ra, có thể sử dụng việc tích hợp Git trong các công cụ quản lý dự án như Jira, Asana.
Các câu hỏi phỏng vấn Git cơ bản (Beginner)
Thế nào là một hệ thống quản lý phiên bản (Version control system)?
Hệ thống quản lý phiên bản (VCS) là một hệ thống lưu giữ các phiên bản của mã nguồn sản phẩm phần mềm. Khi các lập trình viên trong nhóm có những thay đổi trong mã nguồn, thông tin đó sẽ được lưu lại một cách minh bạch bao gồm người thay đổi, thời gian thay đổi, và nội dung thay đổi. VCS giúp các lập trình viên có một cái nhìn thống nhất và tổng quan về dự án đang làm, có thể dễ dàng truy xuất thông tin thay đổi hoặc lấy lại phiên bản mã nguồn trong quá khứ.
Có 3 loại hệ thống quản lý phiên bản phổ biến là:
- Hệ thống quản lý phiên bản cục bộ: Là dạng quản lý phiên bản ngay trên máy tính cá nhân của người dùng.
- Hệ thống quản lý phiên bản tập trung: Là hệ thống gồm một máy chủ chứa toàn bộ dữ liệu phiên bản khác nhau của dự án, và mọi người trong team có thể sử dụng để chia sẻ và truy xuất dữ liệu của nhau.
- Hệ thống quản lý phiên bản phân tán: Mỗi thành viên có bản sao đầy đủ của kho lưu trữ, kết nối với một kho lưu trữ từ xa. Trong trường hợp máy chủ từ xa có trục trặc, thì những thành viên đã tải về trước đó vẫn còn kho lưu trữ, và có thể sử dụng để khôi phục dữ liệu của mã nguồn.
Git là gì và tại sao cần sử dụng Git?
Git là một hệ thống quản lý phiên bản phân tán (Distributed Version Control System – DVCS), giúp theo dõi và quản lý các thay đổi trong mã nguồn hoặc tệp của dự án. Git cho phép làm việc nhóm hiệu quả, duy trì lịch sử thay đổi, và hỗ trợ khôi phục dữ liệu khi cần.
Git là công cụ không thể thiếu để phát triển phần mềm hiệu quả và chuyên nghiệp. Git có những vai trò quan trọng như:
- Theo dõi lịch sử thay đổi: Git lưu chi tiết lịch sử thay đổi mã nguồn, giúp truy vết, khắc phục lỗi, và khôi phục phiên bản ổn định.
- Nâng cao chất lượng làm việc nhóm: Git hỗ trợ phân nhánh và gộp nhánh, giúp lập trình viên làm việc độc lập và hợp nhất dễ dàng, giảm xung đột.
- Lưu trữ và chia sẻ: Git tích hợp với GitHub, GitLab, Bitbucket, đảm bảo mã nguồn an toàn và thuận tiện cho cộng tác nhóm hoặc chia sẻ cộng đồng.
- So sánh thay đổi: Git cho phép so sánh sự khác biệt qua Staging Area và lệnh git diff, giúp kiểm soát thay đổi trước khi cam kết.
Git có ưu điểm gì so với các hệ thống quản lý phiên bản khác
Những ưu điểm của Git so với các hệ thống quản lý phiên bản khác phải kể đến như:
- Khả năng lưu trữ phân tán: Mỗi thành viên trong nhóm đều có bản sao đầy đủ của kho lưu trữ và có thể hoạt động offline. Trong trường hợp máy chủ từ xa có trục trặc, thì những client đã tải về trước đó vẫn còn kho lưu trữ, và có thể sử dụng để khôi phục dữ liệu của mã nguồn.
- Quản lý phiên bản hiệu quả: Điểm nổi bật của Git là khả năng quản lý các phiên bản trong mã nguồn dựa vào các bản chụp nhanh (snapshot) thay đổi của tập tin, thay vì lưu trữ lại sự khác biệt như các hệ thống khác. Với khả năng lưu trữ một cách chi tiết các thông tin về những thay đổi xảy ra đối với mã nguồn, Git giúp các lập trình viên trong dự án có thể truy xuất lại lịch sử thay đổi, phát hiện các nguyên nhân khi hệ thống gặp lỗi.
- Hỗ trợ phân nhánh / hợp nhất nhánh: Tính năng tách nhánh và hợp nhất giúp dễ dàng phát triển tính năng một cách độc lập và dễ dàng hợp nhất các thay đổi từ nhiều thành viên trong nhóm.
- Tích hợp tốt với công cụ hiện đại: Git có thể tích hợp với các nền tảng như GitHub, GitLab, Bitbucket, giúp dễ dàng làm việc nhóm và tích hợp CI/CD.
Sự khác biệt giữa Git và GitHub là gì?
Git là một công cụ kiểm soát phiên bản cho phép bạn theo dõi và ghi lại quá trình phát triển của mã nguồn. GitHub là một dịch vụ lưu trữ trực tuyến giúp quản lý kho lưu trữ Git dễ dàng hơn. Dưới đây là một số điểm so sánh chi tiết:
Tiêu chí | Git | Github |
Chức năng | Quản lý phiên bản của mã nguồn |
|
Phạm vi hoạt động | Nội bộ ở máy tính cá nhân | Trực tuyến thông qua internet |
Quản lý dự án | Không hỗ trợ | Quản lý dự án và cộng tác làm việc thông qua Pull Request, Issues, Project |
Hỗ trợ cộng tác giữa nhiều người | Không hỗ trợ | Cung cấp khả năng cộng tác trực tuyến từ xa |
Làm việc ngoại tuyến | Git hỗ trợ làm việc ngoại tuyến vì tất cả thay đổi được lưu trữ cục bộ. | Yêu cầu internet để truy cập |
CI/CD | Không hỗ trợ | Sử dụng thông qua GitHub Actions hoặc tích hợp với bên thứ ba |
Kể tên một số dịch vụ lưu trữ Git phổ biến hiện nay
Hiện nay trên thị trường có nhiều dịch vụ quản lý mã nguồn trực tuyến khác nhau, mỗi loại đều có những thế mạnh riêng, ví dụ như:
- GitHub: Là dịch vụ lưu trữ Git lớn nhất và phổ biến nhất hiện nay. Tính năng nổi bật của Github là Pull Requets, Issues, Code review và tích hợp CI/CD qua Github Actions.
- GitLab: Dịch vụ lưu trữ mạnh mẽ, cung cấp mã nguồn mở và hỗ trợ lưu trữ trên cloud hoặc tự triển khai (self-hosted). GitLab cung cấp các tính năng quản lý toàn bộ quy trình phát triển phần mềm và tích hợp CI/CD thông qua GitLab CI.
- Bitbucket: Là dịch vụ thuộc hệ sinh thái Atlassian, tích hợp tốt với các công cụ quản lý dự án như Jira, Trello.
Repository là gì? Phân biệt giữa local repository và remote repository
Repository là nơi lưu trữ dự án Git, hay còn gọi là kho lưu trữ. Kho lưu trữ này có thể tồn tại cục bộ trong một thư mục trên máy tính của bạn hoặc trên một nền tảng đám mây như GitHub. Nó bao gồm tất cả các tập tin liên quan đến dự án cùng với bản ghi về các thay đổi đã thực hiện đối với các tập tin này theo thời gian.
- Local Repository là kho lưu trữ trên máy tính cá nhân của lập trình viên. Kho lưu trữ này được sử dụng để thực hiện các thay đổi tại cục bộ và xem lại lịch sử mà không cần kết nối internet.
- Remote Repository là kho lưu trữ trên máy chủ từ xa, được đặt ở bất kỳ đâu. Kho lưu trữ này được xem là nơi hợp nhất các thay đổi trong mã nguồn từ các thành viên, cũng như là phương tiện để lưu trữ và chia sẻ thông tin mã nguồn một cách an toàn. Các đại diện cung cấp dịch vụ này bao gồm Github, Gitlab, Bitbucket,…
Branch trong git là gì?
Trong Git, việc tạo branch cho phép bạn tách ra khỏi luồng phát triển chính và thực hiện các tác vụ riêng biệt mà không ảnh hưởng đến quy trình chính. Sử dụng branch cho phép bạn phát triển độc lập các tính năng, sửa lỗi hoặc thử nghiệm trong một phần cụ thể của kho lưu trữ, đảm bảo mỗi luồng phát triển được giữ riêng biệt với các luồng khác.
Đặc điểm của một branch:
- Tính độc lập: Mỗ branch hoạt động như một bản sao độc lập của mã nguồn. Các thay đổi mới trong branch sẽ không ảnh hưởng đến các branch khác cho đến khi thực hiện hợp nhất branch.
- Tính linh hoạt cao: Một repository có thể tạo nhiều branch, mỗi branch sẽ được sử dụng cho một mục đích khác nhau như phát triển tính năng, sửa lỗi.
Đọc thêm: Git branch: Hướng dẫn chi tiết 10+ thao tác branch cơ bản
Cách để chuyển trạng thái làm việc từ branch này sang branch khác
Để chuyển từ một branch hiện tại sang một branch khác, bạn có thể sử dụng lệnh sau:
Sử dụng lệnh checkout:
git checkout <tên nhánh>
Sử dụng lệnh switch:
git switch <tên nhánh>
Lưu ý, trong trường hợp đang có một số thay đổi chưa được commit và nó sẽ gây xung đột khi chuyển branch, Git sẽ yêu cầu bạn phải xử lý chúng.
- Cách 1: thực hiện commit tất cả các thay đổi hiện tại
- Cách 2: sử dụng git stash để tạm thời lưu trữ những thay đổi
Ví dụ, bạn đang phát triển tính năng ở nhánh feat/login, và đang muốn chuyển về nhánh main để thực hiện kiểm tra mã nguồn:
Sử dụng git stash để lưu trữ tạm thời các thay đổi
git stash
Chuyển sang nhánh main
git switch main
Có những cách nào để tạo một branch?
Để tạo một branch mới, bạn có thể sử dụng cú pháp cơ bản như sau:
git branch <tên branch mới>
Ngoài ra để vừa tạo một branch mới và chuyển ngay sang nhánh vừa tạo, bạn có thể sử dụng câu lệnh:
git checkout -b <tên branch mới>
Hoặc:
git switch -c <tên branch mới>
Commit trong Git là gì, làm sao để tạo một commit?
Mỗi commit trong Git là quá trình ghi lại một phiên bản của các thay đổi hiện tại đã được chuẩn bị trong dự án., nó bao gồm các thông tin sau:
- Danh sách các thay đổi trên các tập tin, gọi là “snapshot”
- Thông tin của người tạo ra commit và thời gian tạo
- Mô tả của commit
Ngoài ra, mỗi commit sẽ được gắn liền với một mã băm duy nhất dài 40 ký tự gọi là SHA-1. Đây được xem như là mã định danh của commit đó và sẽ không có hai SHA-1 nào trùng nhau trong một mã nguồn.
Để tạo mới một commit, bạn cần thực hiện các bước sau:
Kiểm tra những thay đổi hiện tại:
git status
Đưa các tập tin thay đổi vào Staging area:
git add <tên tập tin>
Thực hiện tạo commit:
git commit -m "thông điệp commit"
HEAD trong git là gì?
HEAD trong Git là một con trỏ (pointer) đặc biệt, đại diện cho commit hiện tại mà bạn đang làm việc. Nói cách khác, nó chỉ đến nhánh hoặc commit mà bạn đang “đứng” tại thời điểm đó.
Theo mặc định, HEAD sẽ trỏ đến commit cuối cùng của nhánh hiện tại. Khi bạn thực hiện commit mới, HEAD sẽ tự động cập nhật để trỏ đến commit mới nhất đó.
Khi bạn thực hiện kiểm tra một commit cụ thể bằng việc sử dụng lệnh “git checkout <commit hash>”, HEAD không trỏ đến commit của một nhánh cụ thể mà trỏ trực tiếp đến commit đó. Lúc này, nếu bạn thực hiện thay đổi và commit, các thay đổi đó không được liên kết với nhánh nào. Điều này gọi là Detached HEAD.
Phân biệt giữa working directory và Staging area
Tiêu chí | Working directory | Staging area |
Định nghĩa | Là thư mục làm việc trên máy cục bộ, nơi bạn chỉnh sửa và cập nhật tệp. | Là vùng tạm lưu trữ các thay đổi trước khi commit. |
Vai trò | Là nơi bạn thực hiện chỉnh sửa và phát triển mã nguồn | Chuẩn bị các thay đổi để commit vào lịch sử phiên bản |
Khi thực hiện commit | Các thay đổi trong working directory không được đưa vào commit | Chỉ các thay đổi trong staging index được đưa vào commit |
Vị trí lưu trữ | Trên hệ thống file của máy cục bộ | Bên trong Git, là file ẩn .git/index |
Các lệnh liên quan |
|
|
Những trạng thái chính của một tập tin trong Git
Trong Git, một tập tin có thể được chia làm 2 nhóm trạng thái chính, bao gồm:
- Untracked: Tập tin tồn tại trong thư mục làm việc, nhưng chưa được thêm vào repository và chưa được Git quản lý. Đối với những tập tin này, Git sẽ không theo dõi bất kỳ thay đổi nào.
- Tracked: Là trạng thái sau khi tập tin được thêm vào repository và được quản lý bởi Git. Đối với nhóm này, tập tin có thể có 3 trạng thái sau:
-
- Staged: Các thay đổi của tập tin đã được thêm vào Staging Area và sẵn sàng để commit.
- Committed: Tập tin đã được lưu vào lịch sử Git trong commit gần nhất.
- Modified: Tập tin đã được theo dõi nhưng nội dung của nó đã thay đổi so với phiên bản trong lịch sử Git.
Chúng ta có thể mô tả mối quan hệ giữa chúng thông qua ví dụ sau:
- Tập tin index.html được tạo mới trong thư mục làm việc → tập tin có trạng thái untracked.
- Sử dụng <git add index.html> để thêm tập tin vào Staging Area → tập tin có trạng thái staged.
- Thực hiện lệnh commit để lưu thay đổi → tập tin có trạng thái commited.
- Sau đó thực hiện thay đổi mới trên tập tin → tập tin có trạng thái modified.
Làm sao để đưa các thay đổi từ local repository lên remote repository?
Để đồng bộ những thay đổi từ local repository lên remote repository, bạn sử dụng lệnh push với cú pháp như sau:
git push origin <tên nhánh>
Trong trường hợp đây là lần đầu tiên bạn đẩy mã nguồn lên kho lưu trữ từ xa, bạn có thể thực hiện các bước sau:
Bước 1: Kiểm tra xem remote repository đã được cấu hình chưa:
git remote -v
Nếu chưa, thêm remote repository bằng lệnh:
git remote add origin <remote_repository_url>
Bước 2: Sử dụng tùy chọn -u (upsteam), điều này sẽ thiết lập nhánh hiện tại theo dõi branch tương ứng trên kho lưu trữ từ xa. Những lần thực hiện git push sau đó, bạn không cần phải chỉ định tên nhánh.
git push -u origin <tên nhánh>
Lưu ý, trước khi đẩy các thay đổi từ nhánh ở local repository lên remote repository, bạn nên đồng bộ dữ liệu của nhánh cục bộ so với nhánh từ xa bằng lệnh:
git pull origin <tên nhánh>
Tập tin .gitignore có công dụng gì?
Nội dung trong .gitignore cho Git biết các tập tin và thư mục nào cần bỏ qua khi theo dõi các thay đổi. Nó được sử dụng để tránh đưa các tệp không cần thiết (như nhật ký, tệp tạm thời hoặc mã đã biên dịch) vào kho lưu trữ. Điều này giúp kho lưu trữ sạch sẽ và chỉ tập trung vào các tệp quan trọng, tránh lưu những thông tin nhạy cảm vào kho lưu trữ.
Các câu hỏi phỏng vấn Git trung cấp (Intermediate)
Origin thường ám chỉ đến điều gì?
Trong Git, origin thường ám chỉ đến tên mặc định của remote repository đầu tiên được liên kết với local repository. Nó được sử dụng làm tham chiếu để kiểm soát việc pull, fetch và push giữa local repository và remote repository.
Các trường hợp khởi tạo origin:
Là remote repository mặc định: Khi bạn thực hiện lệnh clone một repository từ một dịch vụ như GitHub, GitLab, hoặc Bitbucket, Git tự động đặt tên cho remote repository đó là origin:
git clone https://github.com/username/repository.git
Được chỉ định khi thực hiện lệnh kết nối giữa local và remote repository:
git remote add origin <remote_url>
Phân biệt giữa git pull và git fetch
Git pull và Git fetch đều là các lệnh dùng để cập nhật mã nguồn mới nhất từ kho lưu trữ từ xa về kho lưu trữ cục bộ, nhưng chúng có sự khác biệt lớn trong cách hoạt động và mục đích sử dụng.
Dưới đây là so sánh chi tiết giữa hai lệnh này:
Tiêu chí | Git fetch | Git Pull |
Cú pháp | git fetch origin main | git pull origin main |
Mục đích | Cập nhật dữ liệu mới từ remote repository nhưng không thay đổi nhánh hiện tại | Lấy về các thay đổi từ remote repository và ngay lập tức hợp nhất (merge) các thay đổi đó vào nhánh hiện tại của bạn |
Hoạt động | Tải về toàn bộ các commits, tags, và các nhánh mới từ remote repository mà chưa có trong kho lưu trữ cục bộ | Mặc định chỉ lấy về commit mới và hợp nhất nó vào nhánh được chỉ định.
Không tự động tải về nhánh mới |
Trường hợp sử dụng | Khi muốn xem trước các thay đổi từ remote
Khi muốn tải về các nhánh mới từ remote |
Khi muốn đồng bộ mã nguồn giữa nhánh cục bộ và nhánh remote một cách nhanh chóng |
Tùy chọn thêm | Không tạo ra commit mới | Có thể dùng –rebase thay vì merge hoặc một số tùy chọn khác |
Làm thế nào để thay đổi commit cuối cùng trong một branch?
Để thay đổi commit cuối cùng, bạn có thể sử dụng lệnh git commit –amend. Đây là lệnh cho phép sửa đổi commit gần nhất, bao gồm thay đổi nội dung hoặc thông điệp commit.
Cách sử dụng:
Bổ sung tập tin vào commit:
- Chỉnh sửa các tập tin mà bạn muốn thêm vào commit cuối cùng
- Thêm thay đổi vào Staging Area bằng git add <tên file>
- Sử dụng lệnh: git commit –amend
- Git sẽ mở trình soạn thảo để bạn có thể sửa thông điệp commit (nếu cần)
- Lưu và đóng trình soạn thảo để hoàn tất
Chỉ sửa thông điệp commit: Sử dụng lệnh sau để sửa thông điệp commit mà không thay đổi nội dung
git commit --amend -m "Thông điệp mới"
Lưu ý, tránh thực hiện chỉnh sửa commit đã được đẩy lên remote repository, vì điều này sẽ gây xung đột mã nguồn đối với các thành viên khác trong dự án.
Làm sao để hoàn tác một commit đã được đẩy lên remote repository?
Cách an toàn để bạn có thể hoàn tác một commit đã đẩy lên remote repository đó là sử dụng lệnh git revert. Cú pháp của lệnh này như sau:
git revert <commit hash>
Lệnh này tạo một commit mới để đảo ngược các thay đổi của commit cũ và giúp giữ nguyên lịch sử commit. Sau đó bạn có thể sử dụng git push để đẩy commit mới lên remote repository.
Ưu điểm của phương pháp này là giúp giữ cho lịch sử commit được toàn vẹn, giúp tránh xung đột khi cộng tác với nhiều người. Từ đó giúp cho lịch sử commit được minh bạch và dễ dàng kiểm tra.
Đọc thêm: Git revert: Hướng dẫn cách hoàn tác lịch sử bằng Git Revert
Trong trường hợp bạn cần loại bỏ hoàn toàn commit cũ khỏi lịch sử commit, bạn có thể sử dụng lệnh git reset với tùy chọn –hard:
git reset --hard <commit>
Lệnh này sẽ loại bỏ commit khỏi lịch sử và không giữ lại các thay đổi. Lưu ý chỉ sử dụng lệnh git reset –hard khi bạn không cần giữ lại lịch sử và chắc chắn rằng các thành viên khác không phụ thuộc vào commit đó.
Đọc thêm: Git Reset: Hướng dẫn cách xóa commit bằng Git Reset
Git cherry-pick là gì?
Git cherry-pick là lệnh dùng để áp dụng một hoặc nhiều commit cụ thể từ một nhánh khác vào nhánh hiện tại (sao chép commits). Điều này rất hữu ích khi bạn chỉ muốn chọn lọc một số thay đổi nhất định mà không muốn hợp nhất toàn bộ nhánh.
Cú pháp cơ bản:
git cherry-pick <commit hash>
Cherry-pick nhiều commit cùng lúc:
git cherry-pick <commit hash1> <commit hash2>
Khi nào nên dùng git cherry-pick?
- Khi bạn cần áp dụng một thay đổi cụ thể từ một nhánh khác nhưng không muốn hợp nhất toàn bộ nhánh.
- Khi bạn muốn sửa lỗi (bug fix) đã được commit trong nhánh khác và áp dụng nó vào nhánh hiện tại.
- Khi cần lấy một tính năng cụ thể từ một nhánh mà không làm xáo trộn mã nguồn của nhánh hiện tại.
Khi nào cần sử dụng git stash?
Git stash là lệnh cho phép bạn tạm thời lưu trữ các thay đổi chưa được commit hiện có trong Working Directory và Staging Index, từ đó trả lại trạng thái ban đầu cho khu vực làm việc. Điều này giúp việc chuyển đổi trạng thái làm việc hoặc xử lý công việc khác mà không gây xung đột, mất dữ liệu.
Cách sử dụng:
Sử dụng git stash để lưu tạm thời các thay đổi:
git stash
Chuyển sang nhánh khác, làm việc xong, rồi quay lại và áp dụng lại thay đổi:
git stash apply
Hoặc áp dụng lại stash và xóa bỏ nó:
git stash apply
Các trường hợp sử dụng git stash:
- Đang làm việc dang dở và cần đồng bộ từ remote repository, lúc này bạn cần thực hiện git pull để lấy các thay đổi từ remote repository, nhưng Git yêu cầu phải commit hoặc xử lý các thay đổi hiện tại trước.
git stash git pull origin <nhánh mục tiêu> git stash pop
- Khi bạn đang làm ở nhánh này nhưng cần chuyển sang một nhánh khác để kiểm tra dữ liệu
git stash git checkout <nhánh mục tiêu>
Xung đột trong git là gì? Nêu các bước để xử lý xung đột
Xung đột xảy ra khi các thay đổi được thực hiện trên cùng một phần của tập tin hoặc các tập tin bởi những người đóng góp khác nhau. Git không thể tự động giải quyết các thay đổi mâu thuẫn này, yêu cầu người dùng phải can thiệp thủ công để xử lý các bất đồng. Điều này thường xảy ra khi:
- Hai hoặc nhiều người cùng chỉnh sửa một tập tin tại cùng một vị trí trong các nhánh khác nhau và xảy ra xung đột khi hợp nhất (merge hoặc rebase).
- Các thay đổi từ remote repository xung đột với thay đổi cục bộ trong quá trình git pull.
- Một số trường hợp khác như khi sử dụng git cherry-pick, git stash apply
Để giải quyết xung đột, các tập tin bị xung đột cần được xem xét và chỉnh sửa dựa trên cách hòa giải phù hợp nhất trước khi phiên bản đã được giải quyết được commit:
- Khi xung đột xảy ra, Git sẽ thông báo trong terminal
- Sử dụng lệnh git status để kiểm tra các tệp bị xung đột
- Mở tập tin đó lên bằng các trình soạn thảo như vscode, sublime text,… để giải quyết. Git sẽ đánh dấu phần mã bị xung đột như sau:
<<<<<<< HEAD # Đây là thay đổi trên nhánh main ... ======= # Đây là thay đổi từ nhánh feature/login ... >>>>>>> main
- Thực hiện xử lý xung đột bằng cách chọn 1 trong 2 nội dung hoặc kết hợp cả 2
- Sau khi chỉnh sửa và lưu tập tin, thêm lại tập tin vào Staging Area:
git add <tên tập tin>
- Tạo commit mới để lưu kết quả:
git commit -m "nội dung commit"
Tag trong git là gì?
Tag là một đối tượng tham chiếu (references) trỏ đến các điểm cụ thể trong lịch sử Git, tương tự như các đánh dấu chương trong một cuốn sách. Bạn có thể tạo tag để trỏ đến một phiên bản phát hành mới, một thay đổi quan trọng trong mã nguồn, hoặc bất kỳ sự kiện nào mà đội ngũ phát triển muốn tham chiếu đến nhằm chỉ định phiên bản phát hành cụ thể (ví dụ: v1.0.1).
Tag giống như một nhánh (branch) nhưng không thay đổi. Khác với nhánh, tag không có lịch sử commit sau khi được tạo (tìm hiểu thêm thông tin về git branch tại đây). Khi một tag được tạo, không thể thêm commit mới vào nó, nhưng bạn có thể dễ dàng tham chiếu bằng tên tag.
Có hai loại tag chính trong Git:
Annotated Tag (Tag có chú thích)
- Lưu trữ thông tin chi tiết như tác giả, ngày giờ, và một thông điệp.
- Được lưu trong cơ sở dữ liệu Git như một đối tượng độc lập.
Lightweight Tag (Tag nhẹ)
Chỉ đơn giản là một con trỏ đến commit, không có thông tin bổ sung.
Đọc thêm: Git Tag: Hướng dẫn chi tiết cách quản lý phiên bản hiệu quả
Cách để tạo một tag tron git?
Tạo Annotated Tag
git tag -a <tag_name> -m "Tag message"
Ví dụ:
git tag -a v1.0 -m "Phiên bản đầu tiên"
Kết quả: Tạo một tag có tên v1.0 với thông điệp “Phiên bản đầu tiên”.
Tạo Lightweight Tag
git tag <tag_name>
Cách sử dụng git merge
Git merge là một lệnh phổ biến trong Git, được sử dụng để hợp nhất các thay đổi (commits) từ một nhánh vào nhánh hiện tại. Đây là công cụ quan trọng để thực hiện gộp nhánh trong quá trình làm việc giữa nhiều luồng phát triển khác nhau trong mã nguồn.
Các trường hợp sử dụng:
- Khi hợp nhất commits từ một nhánh tính năng (feature branch) và nhánh chính (main, master hoặc develop)
- Khi cần đồng bộ hóa nội dung giữa nhánh khác vào nhánh hiện tại
Cú pháp cơ bản:
git merge <tên nhánh>
Ví dụ, để hợp nhất các thay đổi từ nhánh feature-login vào nhánh main, bạn có thể thực hiện như sau:
Bước 1: Chuyển sang nhánh main
git checkout main
Bước 2: Hợp nhất nhánh feature-login vào main
git merge feature-login
Đọc thêm: Git Merge: Hướng dẫn chi tiết cách sử dụng Git Merge
Các câu hỏi phỏng vấn Git nâng cao (Advanced)
Tại sao lệnh git pull hoặc git push có thể bị git từ chối thực thi?
Lệnh git pull hoặc git push trong Git có thể bị từ chối bởi nhiều nguyên nhân khác nhau, thường liên quan đến xung đột lịch sử, hoặc cấu hình nhánh. Dưới đây là các lý do phổ biến và cách giải quyết:
Lệnh git pull bị từ chối
Thay đổi cục bộ chưa được commit
- Nguyên nhân: Kho lưu trữ cục bộ có thay đổi chưa được commit trong thư mục làm việc, và Git không thể hợp nhất chúng với thay đổi từ remote repository.
- Cách xử lý: Commit hoặc stash thay đổi cục bộ sau đó thực hiện lại lệnh pull
Xung đột trong quá trình hợp nhất
- Nguyên nhân: Mã nguồn trên remote repository đã được chỉnh sửa, và thay đổi đó xung đột với các thay đổi cục bộ
- Cách xử lý: Giải quyết xung đột bằng cách chỉnh sửa các tập tin được chỉ định và thực hiện commit nội dung đã xử lý.
Lệnh git push bị từ chối
Xung đột lịch sử (non-fast-forward)
- Nguyên nhân: Remote repository đã có các commit mới không tồn tại trong nhánh local của bạn. Git yêu cầu bạn đồng bộ trước khi push.
- Cách xử lý: Thực hiện pull code mới từ remote repository về và thực hiện lại lệnh push.
Xung đột do force push từ người khác
- Nguyên nhân: Thành viên khác đã sử dụng git push –force để đẩy các thay đổi lên remote repository, làm lịch sử của nhánh remote khác với nhánh local của bạn.
- Cách xử lý: Đồng bộ nhánh local với remote và xử lý xung đột xảy ra, sau đó thực hiện lại lệnh push
Xung đột do nhánh cục bộ có sự thay đổi lịch sử
- Nguyên nhân: Bạn sử dụng git reset, git commit –amend để thay đổi commit đã được đẩy lên remote repository trước đó, dẫn đến có sự khách nhau về lịch sử commit giữa cục bộ và kho từ xa.
- Cách xử lý: Sử dụng cờ –force trong lệnh push, tuy nhiên cần đảm bảo điều này không gây mất dữ liệu trên kho từ xa và không gây xung đột với tmã nguồn của hành viên khác.
So sánh giữa git reset và git revert
Git reset và Git revert được sử dụng để hoàn tác các thay đổi trong repository. Tuy nhiên cơ chế hoạt động của chúng lại hoàn toàn khác nhau:
Tiêu chí | Git reset | Git revert |
Cú pháp | git reset <options> <commit> | git revert <commit> |
Cơ chế hoạt động | Hoàn tác commit bằng cách thay đổi lịch sử, vị trí con trỏ HEAD | Tạo commit mới với nội dung đảo ngược so với commit cần hoàn tác |
Thay đổi lịch sử commit | Thay đổi lịch sử commit (xóa bỏ commit khỏi lịch sử) | Giữ nguyên lịch sử, chỉ bổ sung commit đảo ngược |
Thay đổi Staging Area, Working Directory | Có thể làm thay đổi tùy thuộc vào cơ chế sử dụng | Không làm thay đổi |
Phạm vi sử dụng | Chỉ nên sử dụng ở nhánh cục bộ, chưa được đẩy lên remote repository | An toàn khi sử dụng trên remote repository |
Trường hợp sử dụng | Xóa commit khỏi lịch sử và không lưu lại dấu vết | Khi cần hoàn tác commit nhưng vẫn giữ nguyên lịch sử |
Khi nào nên sử dụng git rebase?
Git rebase là một lệnh mạnh mẽ trong git để hợp nhất các thay đổi từ nhánh này sang nhánh khác bằng việc tái sắp xếp lại lịch sử commits. Git rebase sẽ đưa những commit mới của nhánh hiện tại lên phía đầu trong lịch sử commit và tạo ra một lịch sử commit tuyến tính.
Cú pháp cơ bản của git rebase:
git rebase <tên nhánh>
Git rebase hoạt động dựa trên cơ chế sắp xếp lại lịch sử commit và không tạo ra commit merge. Điều này sẽ hình thành một lịch sử commit tuyến tính. Git rebase rất phù hợp trong những trường hợp như:
- Cập nhật thay đổi từ nhánh gốc nhưng không muốn tạo ra commit merge.
- Muốn giữ cho lịch sử commit được gọn gàng và sạch sẽ: Bởi vì cơ chế tái tạo một lịch sử commit tuyến tính và không tạo ra commit merge nên git rebase rất phù hợp cho những dự án cần giữ lịch sử đơn giản và gọn gàng.
- Cần tái sử dụng một nhánh hoặc sắp xếp lại commit trên một commit base mới.
- Khi làm việc trên nhánh riêng và muốn cập nhật từ nhánh chính: Giữ nhánh riêng (feature branch) của bạn luôn đồng bộ với nhánh chính, nhưng không làm xáo trộn lịch sử của nhánh chính.
Đọc thêm: Git rebase: Hướng dẫn sử dụng từ cơ bản đến nâng cao
Phân biệt giữa git rebase và git merge
Git rebase và Git merge đều là những phương pháp được sử dụng để hợp nhất các thay đổi từ nhánh này vào nhánh khác trong Git, nhưng giữa chúng có những đặc điểm khác nhau.
Dưới đây là bảng so sánh chi tiết giữa Git rebase và Git merge, giúp bạn có thể lựa chọn phương pháp phù hợp:
Tiêu chí | Git rebase | Git merge |
Cú pháp | git rebase <tên nhánh> | git merge <tên nhánh> |
Tạo ra merge commit | Không | Có (trường hợp cả hai nhánh đều có thay đổi mới) |
Lịch sử commit | Lịch sử commit được chỉnh sửa lại, các commit từ nhánh nguồn sẽ được “sao chép” vào nhánh hiện tại. | Lịch sử của hai nhánh được giữ nguyên, tạo thêm một commit hợp nhất (merge commit). |
Cách hiển thị lịch sử | Tạo ra lịch sử tuyến tính, không có rẽ nhánh hay merge commit | Lịch sử không tuyến tính, có các nhánh rẽ và merge commit, phản ánh quá trình phát triển thực tế. |
Xử lý xung đột | Có thể cần xử lý xung đột nhiều lần đối với từng commit khi rebase | Xử lý xung đột một lần duy nhất trong quá trình merge |
Trường hợp sử dụng |
|
|
Khả năng tiếp cận | Yêu cầu hiểu rõ quy trình, đặc biệt khi có nhiều xung đột. | Dễ sử dụng hơn, phù hợp với hầu hết các tình huống. |
Hợp nhất fast-forward là gì?
Hợp nhất Fast-Forward trong Git là một kiểu merge đặc biệt xảy ra khi nhánh đích không có commit nào mới kể từ khi tách nhánh nguồn. Trong trường hợp này, Git chỉ cần “di chuyển” con trỏ (HEAD) của nhánh đích lên commit mới nhất của nhánh nguồn mà không tạo ra commit hợp nhất (merge commit).
Đặc điểm của Fast-forward merge:
- Không tạo ra commit merge
- Lịch sử commit được tuyến tính
- Thực hiện mặc định khi nhánh hiện tại không có thêm commit mới khác
Ưu điểm của Fast-Forward Merge
- Lịch sử gọn gàng: Giữ lịch sử tuyến tính, dễ đọc.
- Nhanh chóng: Không tạo thêm commit hợp nhất, giảm dung lượng lịch sử.
Nhược điểm của Fast-Forward Merge
- Khó xác định điểm hợp nhất: Khi làm việc nhóm, việc không có merge commit có thể gây khó khăn trong việc theo dõi lịch sử hợp nhất.
- Không phù hợp cho nhánh dài hạn: Với các nhánh tồn tại lâu dài (ví dụ: develop hoặc release), không tạo merge commit có thể làm mất dấu mốc quan trọng.
Cách khôi phục một branch đã bị xóa
Để khôi phục một branch đã bị xóa, bạn có thể dựa vào git reflog. Git reflog là một nhật ký tham chiếu (reference log) lưu trữ danh sách theo thứ tự thời gian của tất cả các thay đổi đã được thực hiện đối với con trỏ HEAD trong repository Git của bạn. HEAD luôn trỏ đến commit mới nhất, và reflog về cơ bản theo dõi mọi commit trước đây từng tồn tại trong repository.
Khi một nhánh bị xóa, commit cuối cùng của nhánh vẫn được lưu trong git reflog. Để khôi phục lại nhánh, bạn có thể làm như sau:
- Mở git reflog và tìm đến vị trí commit cuối cùng của nhánh
- Sử dụng switch hoặc checkout để tách ra một nhánh mới với lịch sử đó
git switch -c <tên nhánh> <vị trí commit>
Hãy kể tên một số quy trình Git Workflow phổ biến
Git workflow là một quy trình làm việc hoặc phương pháp tổ chức việc sử dụng Git trong quản lý mã nguồn. Ngày nay, có rất nhiều workflow phù hợp với nhiều loại dự án, bao gồm:
- Centralized Workflow: quy trình làm việc tập trung sử dụng một kho lưu trữ trung tâm làm điểm truy cập duy nhất cho tất cả các thay đổi của dự án. Nhánh phát triển mặc định được gọi là “main” và tất cả các thay đổi được commit vào nhánh này. Quy trình này không yêu cầu bất kỳ nhánh nào khác ngoài “main”.
- GitHub Flow: tập trung vào việc phát triển trên nhánh chính và triển khai nhanh chóng các thay đổi vào môi trường sản xuất. Xuyên suốt quá trình làm việc, Github Flow sẽ tập trung vào nhánh gốc (main hoặc master), các tính năng mới sẽ được thao tác trên các nhánh feature (tách ra từ nhánh gốc) và sau đó hợp nhất vào nhánh gốc khi hoàn thành tính năng.
- Feature Branch Workflow: trong workflow này, mỗi tính năng mới cần được phát triển trên một nhánh riêng biệt, tách biệt hoàn toàn khỏi nhánh chính (main hoặc master). Đặc thù của quy trình này là sẽ có một nhánh chính tồn tại xuyên suốt quá trình phát triển, song song với đó là những nhánh ngắn hạn (chỉ tồn tại trong thời điểm phát triển một tính năng, và sẽ loại bỏ sau khi hợp nhất vào nhánh chính).
- Gitflow Workflow: là một mô hình nhánh (branching model) thay thế trong Git, sử dụng các nhánh tính năng (feature branch) và nhiều nhánh chính (primary branch). Theo mô hình này, các nhà phát triển tạo một nhánh tính năng và chỉ hợp nhất (merge) nó vào nhánh chính khi tính năng đã hoàn thành.
- Forking Workflow: Forking Workflow về cơ bản khác với các quy trình quản lý công việc Git phổ biến khác. 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ã “trung tâm”, nó cung cấp cho nhà phát triển kho lưu trữ phía máy chủ của riêng họ. Đ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 lưu trữ Git: một kho lưu trữ cục bộ riêng tư và một kho lưu trữ phía máy chủ công khai.
Đọc thêm: Git Workflow: Cách áp dụng kỹ thuật quản lý mã nguồn hiệu quả
Làm thế nào để gộp nhiều commit vào một commit?
Để gộp nhiều commits thành một commit bạn có thể sử dụng theo 2 cách sau:
Sử dụng Interactive rebase
Đây là một chức năng mạnh mẽ cung cấp nhiều tùy chọn linh hoạt để chỉnh sửa lịch sử commit.
Cú pháp khởi tạo:
git rebase -i <base>
Trong đó, <base> là phạm vi commit cần được thao tác:
- HEAD~n: bắt đầu từ commit đứng trước n commit gần nhất và thao tác trên n commit gần nhất.
- <commit-hash>: bắt đầu từ commit ngay sau commit có hash này và thao tác trên tất cả các commit từ đó đến HEAD.
Để làm rõ cách sử dụng Interactive rebase để gộp commits, chúng ta hãy cùng xem qua ví dụ sau:
Giả sử ta có nhánh develop với các commit như sau:
07ce17d (HEAD -> develop) commit 4 8d01940 commit 3 545b48e commit 2 d400fbb commit 1
Bây giờ, nếu chúng ta muốn gộp hai commit 2 và 3 thành 1 commit mới, để giảm bớt số lượng commit, ta có thể làm theo các bước sau:
Bước 1: Thực hiện rebase -i với commit hash là commit 1
git rebase -i d400fbb
Bước 2: thay chữ “pick” ở trước commit 3 thành chữ “squash”
squash 8d01940 commit 3 pick 545b48e commit 2 pick d400fbb commit 4
Bước 3: Lưu và thoát. Git sẽ thực hiện gộp commit 3 với commit trước nó là commit 2, sau đó sẽ tự động mở trình soạn thảo để bạn bổ sung thông điệp cho commit mới
Bước 4: Sau khi thêm thông điệp và thoát, lịch sử commit mới sẽ có dạng:
07ce17d (HEAD -> develop) commit 4 16acfbf squash commit 2 & 3 d400fbb commit 1
Sử dụng git reset
Bước 1: Kiểm tra lịch sử commit
Sử dụng lệnh git log –oneline để xem danh sách các commit gần nhất:
git log --oneline
Ví dụ kết quả:
g7h8i9 Commit 3 d4e5f6 Commit 2 a1b2c3 Commit 1
Bước 2: Sử dụng git reset với tùy chọn là –soft để đưa các thay đổi trong commit về lại khu vực Staging
git reset --soft HEAD~<số commit>
Ví dụ, nếu bạn muốn gộp 3 commit gần nhất:
git reset --soft HEAD~3
Bước 3: Sau khi reset, 3 commit đó sẽ bị xóa khỏi lịch sử và tất cả các thay đổi từ các commit sẽ được đưa vào Staging Area. Bây giờ bạn thực hiện tạo một commit mới với nội dung thay đổi tổng hợp từ 3 commit đó:
git commit -m "thông điệp"
Tổng kết
Ngày nay, Git với vai trò là một công cụ quản lý mã nguồn mạnh mẽ, đã trở thành một trợ thủ đắc lực trong các dự án phát triển phần mềm. Việc hiểu rõ và sử dụng thành thạo Git không chỉ giúp bạn nâng cao chất lượng công việc và còn là kỹ năng được đánh giá cao trong các buổi phỏng vấn. Với bộ câu hỏi phỏng vấn Git nhiều cấp độ kể trên, ITviec chúc bạn thành công trong buổi phỏng vấn sắp tới!