Git Pro: Những thao tác cơ bản khi làm việc với Git (P1)

Bạn đã nắm được một số khái niệm cơ bản và cơ chế hoạt động của Git thông qua Chương 1 . Trong chương này chúng ta sẽ đi vào một số hoạt động cụ thể khi làm việc với Git.

Đây là chương giúp bạn bắt đầu làm việc với Git, bao gồm các lệnh cơ bản bạn cần thao tác để quản lý dự án của mình. Đến cuối chương, bạn có thể định cấu hình và khởi tạo kho lưu trữ(repo), bắt đầu và dừng theo dõi các tệp(tracking files), giai đoạn(stage) và thay đổi cam kết(commit). Chúng tôi cũng sẽ chỉ cho bạn cách thiết lập Git để bỏ qua các tệp và mẫu tệp nhất định, cách để hoàn tác nhanh chóng và dễ dàng, cách duyệt lịch sử dự án của bạn và xem các thay đổi giữa các lần xác nhận và cách đẩy(push) và kéo(pull) từ kho lưu trữ.

2.1 Kho lưu trữ Git – Git repo

Nhận một kho lưu trữ Git

Bạn thường có được một kho lưu trữ Git theo một trong hai cách:

  1. Bạn có thể lấy một thư mục local hiện không bị kiểm soát và biến nó thành kho lưu trữ Git hoặc
  2. Bạn có thể clone một kho lưu trữ Git hiện đã có.

Sau khi dùng một trong hai cách trên, bạn có được kho Git trên máy local của mình, sẵn sàng cho công việc.

Khởi tạo một kho lưu trữ trong một thư mục hiện có

Nếu bạn có một thư mục chứa một dự án hiện không được kiểm soát và bạn muốn bắt đầu kiểm soát nó bằng Git, trước tiên bạn cần phải đi đến thư mục của dự án đó. Tùy thuộc vào từng hệ thống bạn đang chạy:

cho Linux:

cho macOS:

cho Windown:

và gõ:

Lệnh này tạo ra một thư mục con mới có tên .git chứa tất cả các tệp cần thiết của bạn – bộ xương kho lưu trữ Git. Tại thời điểm này, không có gì trong dự án của bạn được theo dõi. (Xem Git Internals để biết thêm thông tin về chính xác những tập tin được chứa trong .git bạn vừa tạo.)

Nếu bạn muốn bắt đầu kiểm soát các tệp hiện có (không phải thư mục trống), bạn nên bắt đầu theo dõi các tệp đó và thực hiện commit ban đầu. Bạn có thể thực hiện điều đó với  git add chỉ định các tệp bạn muốn theo dõi, sau đó là git commit :

Sau khi lệnh trên kết thúc, bạn có một kho lưu trữ Git với các tệp được theo dõi và một cam kết ban đầu.

Clone một kho lưu trữ hiện có

Nếu bạn muốn lấy một bản sao của kho Git hiện có – ví dụ: một dự án bạn muốn đóng góp – lệnh bạn cần là git clone . Nếu bạn quen thuộc với các hệ thống VCS khác như Subversion, bạn sẽ thấy rằng lệnh là “clone” chứ không phải “checkout”. Đây là một điểm khác biệt quan trọng – thay vì chỉ nhận một bản sao hoạt động, Git nhận được một bản sao gần như đầy đủ tất cả dữ liệu mà máy chủ có. Mọi version của mỗi tệp của dự án được kéo xuống theo mặc định khi bạn chạy git clone . Trên thực tế, nếu đĩa máy chủ của bạn bị hỏng, bạn có thể sử dụng gần như bất kỳ bản sao nào trên máy khách bất kỳ để đặt máy chủ trở lại trạng thái khi nó được clone (bạn có thể mất một số hook phía máy chủ, nhưng tất cả dữ liệu của version này sẽ ở đó – xem Getting Git on a Server để biết thêm chi tiết).

Bạn clone một kho lưu trữ với git clone <url> . Ví dụ: nếu bạn muốn sao chép thư viện liên kết Git có tên libgit2 , bạn có thể làm như sau:

Lệnh trên tạo ra một thư mục có tên libgit2 , khởi tạo .git bên trong nó, lấy xuống toàn bộ dữ liệu của kho lưu trữ đó và kiểm tra một bản sao hoạt động của phiên bản mới nhất. Nếu bạn đi vào thư mục libgit2 mới được tạo, bạn sẽ thấy các tệp của dự án sẵn sàng để làm việc hay sử dụng.

Nếu bạn muốn sao chép kho lưu trữ vào một thư mục có tên khác với libgit2 , bạn có thể chỉ định tên thư mục mới làm đối số bổ sung:

Lệnh đó thực hiện tương tự như lệnh trước, nhưng thư mục đích được gọi là mylibgit .

Git có một số giao thức khác nhau mà bạn có thể sử dụng. Ví dụ trước sử dụng giao thức https:// , nhưng bạn cũng có thể thấy git:// hoặc user@server:path/to/repo.git , sử dụng giao thức truyền SSH. Getting Git on a Server  sẽ giới thiệu các tùy chọn mà máy chủ có thể thiết lập để truy cập vào kho Git của bạn và ưu và nhược điểm của từng tùy chọn.

2.2 Ghi lại những thay đổi vào repository

Ghi lại thay đổi vào kho lưu trữ

Tại thời điểm này, bạn nên có một kho lưu trữ Git thực sự trên máy local của mình và kiểm tra hoặc sao chép tất cả các tệp của nó. Thông thường, bạn muốn bắt đầu thực hiện các thay đổi và commit những thay đổi đó vào kho lưu trữ của bạn mỗi khi dự án đạt đến trạng thái bạn muốn ghi lại.

Các file trong thư mục của bạn có hai trạng thái: tracked hoặc untracked tức là được theo dõi hoặc không được theo dõi.

Tracked file là những file được git theo dõi, những file này có thể không được sửa đổi, sửa đổi hoặc dàn dựng(unmodified, modified hoặc staged).

Untracked file là những file còn lại. Khi bạn clone một git repo thì tất cả các file bạn có là tracked và unmodified. Nếu không được cấp quyền, bạn không thể sửa đổi bất kỳ thứ gì trên repo này.

Quá trình theo dõi các file của Git được thực hiện như sau:

 

Quá trình từ lần commit này đến lần commit kế tiếp sẽ được coi là một Stage. Khi bạn thêm/sửa một file bất kỳ Git nhận thấy sự thay đổi so với lần commit cuối cùng, bạn cần commit để ghi lại những thay đổi bạn đã thực hiện và tiếp tục lặp lại chu kỳ với Staged tiếp theo.

Kiểm tra trạng thái tệp của bạn

Công cụ chính bạn sử dụng để xác định tập tin nào ở trạng thái nào là git status . Nếu bạn chạy lệnh này trực tiếp sau khi clone, bạn sẽ thấy thông tin hiển thị như sau:

Thường thì ngay sau khi clone một git repo bạn thực hiện lệnh trên sẽ cho kết quả ở nhánh master

Giả sử bạn thêm một tệp mới vào dự án của mình, một tệp README. Nếu tệp không tồn tại trước đó và bạn chạy git status , bạn sẽ thấy thông tin như sau:

Bạn có thể thấy rằng tệp README mới của bạn untracked, bởi vì nó nằm dưới “Untracked files”. Untracked về cơ bản có nghĩa là Git nhìn thấy một tệp mà bạn không commit ở lần commit trước đó; Git sẽ không theo dõi file này của bạn cho đến khi bạn chỉ định cho Git theo dõi nó. Bạn muốn theo dõi README vậy hãy bắt đầu theo dõi tệp.

Theo dõi tập tin mới

Để bắt đầu theo dõi một tệp mới, bạn sử dụng lệnh git add . Để bắt đầu theo dõi tệp README , bạn chạy lệnh:

Nếu bạn chạy lại lệnh kiểm tra trạng thái, bạn có thể thấy rằng tệp README của bạn hiện được theo dõi và trong stage để được commit:

Ta có thể nói rằng nó trong stage bởi vì nó nằm dưới tiêu đề “Changes to be committed”. Nếu bạn commit tại thời điểm này, version của file tại thời điểm bạn chạy git add là những gì sẽ có trong snapshot tiếp theo. Nhớ lại trước đo khi bạn chạy git init , thì bạn đã chạy git add <files> – việc này bắt đầu theo dõi các tệp trong thư mục của bạn. Lệnh git add lấy tên đường dẫn cho tệp hoặc thư mục; nếu đó là một thư mục, lệnh sẽ thêm tất cả các tệp trong thư mục đó theo cách đệ quy.

Staging các tập tin được sửa đổi

Hãy thay đổi một tập tin đã được theo dõi. Nếu bạn thay đổi một tệp được theo dõi trước đó có tên CONTRIBUTING.md và sau đó chạy lại git status , bạn sẽ nhận được một thông báo như thế này:

CONTRIBUTING.md xuất hiện trong phần “Changes not staged for commit” – có nghĩa là một tệp đang được theo dõi đã bị sửa đổi nhưng chưa được staged. Để staged, bạn chạy git add . Đây là một lệnh đa năng – nó dùng để bắt đầu theo dõi các tệp mới, stage file và để thực hiện các việc khác như merge-conflicted files giống như resolved. Giờ hãy chạy git add để tạo tập tin CONTRIBUTING.md và sau đó chạy lại git status :

Cả hai tập tin đều staged và sẽ đi vào commit tiếp theo của bạn. Tại thời điểm này, giả sử bạn cần một vài thay đổi nhỏ mà bạn muốn thực hiện trước khi bạn commit trong CONTRIBUTING.md . Bạn mở lại rồi thực hiện thay đổi, và bạn đã sẵn sàng commit. Tuy nhiên, hãy chạy git status một lần nữa:

Hiện tại CONTRIBUTING.md nằm trong cả staged  unstaged. Vì sao lại như thế? Bởi vì Git tạo ra một tệp, nó giống như khi bạn chạy git add . Nếu hiện tại bạn commit, version CONTRIBUTING.md sẽ giống lần cuối bạn chạy git add . Nếu bạn sửa đổi một tệp sau khi bạn chạy git add , bạn phải chạy lại git add để tạo version mới nhất của tệp:

Status rút gọn

Mặc dù output của lệnh git status khá đầy đủ, nhưng nó vẫn dài dòng. Bạn có thể thấy output gọn gàng hơn khi bạn chạy git status -s hoặc git status --short :

Các tệp mới không được theo dõi có "??" bên cạnh, các tệp mới đã được thêm vào khu vực staging A , các tệp modified M và …. Output có hai cột – cột bên trái thể hiện khu vực staging và cột bên phải cho biết trạng thái của cây làm việc. Vì vậy, ví dụ với output trên, tệp README ở trạng thái đã sửa đổi nhưng chưa staged, tệp lib/simplegit.rb ở trạng thái đã sửa đổi và staged. Rakefile ở trạng thái đã được sửa đổi, stage và sau đó được sửa đổi một lần nữa, vì vậy có những thay đổi đối với cả hai stage và unstage.

Ignoring Files

Thông thường, bạn sẽ có một lớp các tệp mà bạn không muốn Git tự động thêm hoặc thậm chí hiển thị cho bạn là không bị theo dõi. Đây thường là các tệp được tạo tự động như tệp log hoặc tệp do hệ thống của bạn tạo ra. Trong các trường hợp như vậy, bạn có thể tạo một mẫu liệt kê tệp để khớp với chúng có tên .gitignore . Dưới đây là một ví dụ .gitignore tệp:

Dòng đầu tiên yêu cầu Git bỏ qua mọi tệp kết thúc bằng “.o” or “.a” . Dòng thứ hai yêu cầu Git bỏ qua tất cả các tệp có tên kết thúc bằng dấu ( ~ ).  Thiết lập tệp .gitignore cho kho lưu trữ mới trước khi bạn bắt đầu quản lý dự án là một ý tưởng tốt giúp bạn không vô tình cam kết các tệp mà bạn thực sự không muốn trong kho Git của mình.

Các quy tắc bạn có thể đặt trong tệp .gitignore như sau:

  • Các dòng trống hoặc đầu dòng là # được bỏ qua.
  • Áp dụng đệ quy trên toàn bộ cây làm việc.
  • Bạn có thể bắt đầu bằng dấu gạch chéo ( / ) để tránh đệ quy.
  • Bạn có thể kết thúc bằng dấu gạch chéo ( / ) để chỉ định thư mục.
  • Bạn có thể phủ định bằng cách đặt dấu chấm than ( ! ) vào đầu.

Dấu hoa thị ( * ) tương đương với 0 hoặc nhiều ký tự; [abc] tương đương với bất kỳ ký tự nào trong dấu ngoặc ( a, b hoặc c); dấu hỏi ( ? ) tương đương với một ký tự đơn; và ( [0-9] ) tương đương với bất kỳ ký tự nào giữa chúng ( 0 đến 9). Bạn cũng có thể sử dụng hai dấu sao để khớp các thư mục lồng nhau; a/**/z sẽ tương đương với a/z , a/b/z , a/b/c/z , v.v.

Một ví dụ khác của tệp .gitignore :

Xem các thay đổi theo stage và unstage

Nếu git status chưa đủ chi tiết như bạn muốn – bạn muốn biết chính xác những gì đã thay đổi – bạn có thể sử dụng git diff . Khigit status đưa ra thông tin chung chung bằng cách liệt kê tên tệp, git diff hiển thị cho bạn các dòng chính xác được thêm và xóa đi.

Giả sử bạn chỉnh sửa và xử lý tệp README sau đó chỉnh sửa tệp CONTRIBUTING.md mà unstage nó. Nếu chạy git status , bạn sẽ thấy thông tin như sau:

Để xem những gì bạn đã thay đổi nhưng chưa được staged, hãy nhập git diff :

Nếu bạn muốn xem những gì staged được commit trong lần tiếp theo, sử dụng git diff --staged . Lệnh này so sánh các thay đổi theo stage với commit cuối cùng của bạn:

Điều cần lưu ý là bản thân lệnh git diff không hiển thị tất cả các thay đổi được thực hiện kể từ lần commit cuối cùng – những file thay đổi nhưng vẫn unstaged.

Một ví dụ khác, bạn tạo tập tin CONTRIBUTING.md và sau đó chỉnh sửa nó, bạn có thể sử dụng git diff để xem các thay đổi trong tệp được stage và các thay đổi không được thực hiện. Như sau:

Bây giờ bạn có thể sử dụng git diff để xem những gì vẫn unstaged:

và git diff –cached để xem những gì được staged cho đến nay (–staged và –cached có ý nghĩa như nhau):

Commit những gì bạn đã thay đổi

Hiện tại stage đã như bạn mong muốn, bạn có thể commit thay đổi của mình. Hãy nhớ rằng bất cứ tệp nào unstaged – bất kỳ tệp nào bạn đã tạo hoặc sửa đổi mà bạn chưa chạy git add kể từ khi bạn chỉnh sửa chúng – sẽ không đi vào commit này. Trường hợp này, giả sử bạn chạy git status và thấy rằng mọi thứ đều staged, bạn sẵn sàng commit cách thay đổi này. Cách đơn giản nhất là nhập git commit :

Thông tin sau được hiển thị (ví dụ màn hình Vim):

Ta thấy rằng thông báo commit mặc định chứa output mới nhất của git status  và một dòng trống ở trên cùng. Bạn có thể xóa những bình luận này và nhập thông tin commit của bạn. Bạn cũng có thể để chúng ở đó để giúp bạn nhớ những gì bạn đang commit.

Bạn cũng có thể nhập nội dung thông điệp commit  bằng lệnh commit chỉ định nó sau cờ -m , như sau:

Giờ bạn đã tạo commit thành công. Bạn có thể output của lệnh commit như:bạn đã commit trên nhánh (branch) nào ( master ),  SHA-1 mà commit có ( 463dc4f ), có bao nhiêu tệp đã được thay đổi và số dòng được thêm và xóa trong commit.

Hãy nhớ rằng commit ghi lại snapshot bạn thiết lập trong staging của bạn. Bất cứ file nào không stage vẫn ở đó; bạn có thể thực hiện một commit khác để thêm nó vào lịch sử của bạn. Mỗi khi bạn thực hiện một commit, bạn đang ghi lại một snapshot, bạn có thể quay lại hoặc so sánh chúng với những gì của sau này.

Bỏ qua staging

Đôi khi staging có hơi phức tạp so với những gì cần trong quy trình làm việc. Nếu bạn muốn bỏ qua staging, Git cung cấp một phím tắt đơn giản là thêm tùy chọn -a vào git commit giúp Git tự động tạo stage cho mọi tệp đã được theo dõi trước khi thực hiện commit, cho phép bạn bỏ qua phần git add :

Lưu ý cách bạn không cần chạy git add trên tệp CONTRIBUTING.md trước khi bạn commit. Bởi vì -a bao gồm tất cả các tệp đã thay đổi. Việc này rất thuận tiện nhưng hãy cẩn thận; vì lệnh này có thể bao gồm những thay đổi mà bạn không mong muốn.

Xóa tệp

Để xóa một tệp khỏi Git, bạn phải xóa nó khỏi các tệp được theo dõi của bạn (chính xác là xóa nó khỏi staging của bạn) và sau đó commit. Lệnh git rm thực hiện điều đó.

Nếu bạn chỉ đơn giản xóa tệp khỏi thư mục làm việc của mình, thì nó sẽ hiển thị trong phần “Changes not staged for commit” (nghĩa là unstaged) trong output của lệnh git status :

Sau đó, nếu bạn chạy git rm , nó sẽ loại bỏ tệp:

Lần commit tiếp theo, tập tin sẽ không còn và không còn được theo dõi. Nếu bạn đã sửa đổi tệp hoặc đã thêm nó vào staging, bạn bắt buộc pahir xóa bằng tùy chọn -f . Đây là một tính năng an toàn giúp ngăn việc vô tình xóa dữ liệu chưa được ghi lại trong snapshot và không thể khôi phục được từ Git.

Một việc khác mà bạn có thể muốn làm là giữ tệp trong cây làm việc, nhưng xóa nó khỏi staging của bạn. Nói cách khác, bạn có thể muốn giữ tệp trên ổ cứng của mình nhưng Git không theo dõi nó nữa. Nó sẽ rất hữu ích khi bạn quên thêm tệp không cần theo dõi vào tệp .gitignore. Để làm điều này, sử dụng tùy chọn --cached :

Bạn có thể truyền các tệp, thư mục cho git rm . Nghĩa là bạn có thể làm những việc như:

Lưu ý dấu gạch chéo ngược ( \ ) phía trước dấu * . Nó rất cần thiết vì Git thực hiện mở rộng tên tệp của riêng mình ngoài việc mở rộng tên tệp của shell. Lệnh này loại bỏ tất cả các tệp .log trong thư mục log/ . Hoặc, bạn có thể làm như sau:

Lệnh này sẽ xóa tất cả các tệp có tên kết thúc bằng a ~ .

Di chuyển tập tin

Không giống như nhiều hệ thống VCS khác, Git không theo dõi rõ ràng sự di chuyển của tệp. Nếu bạn đổi tên tệp trong Git, Git không thể cho biết rằng bạn đã đổi tên tệp.

Do đó, Git có lệnh mv . Nếu bạn muốn đổi tên một tệp trong Git, bạn có thể chạy:

Trên thực tế, nếu bạn chạy một file như thế này và kiểm tra status, bạn sẽ thấy Git coi đó là một tệp được đổi tên:

Nó tương đương với việc:

Git chỉ ra rằng đó là một sự đổi tên ngầm, vì vậy sẽ không có vấn đề gì nếu bạn đổi tên một tệp theo cách đó hoặc bằng lệnh mv . Khác biệt duy nhất là thay vì ba lệnh giờ chỉ có một lệnh git mv – nó tiện lợi hơn.

Trong phần này, các bạn đã thấy được cách làm việc cơ bản của Git. Các lệnh cơ bản thường được sử dụng trong Git và ý nghĩa của chúng. Chưa dừng lại ở đây, chúng ta sẽ tiếp tục tìm hiểu về lịch sử commit và học cách làm sao để hoàn tác trong bài tiếp theo.

Tags:

Add a Comment

Your email address will not be published.