Uploaded by dth1617tranthientrong12a6

GIT

advertisement
Biên Soạn: Trần Thiên Trọng – tranthientrong.it@gmail.com
BASIC
Version Control System
A version control system ( VCS ), theo dõi lịch sử thay đổi của file, khi bạn modify file, VCS sẽ ghi lại và lưu từng thay đổi. Cho phép bạn khôi phục phiên bản trước
đó của bất kỳ lúc nào.
In short, a Version Control System like Git makes it easy to:
• Keep track of code history
• Collaborate on code as a team
• See who made which changes
• Deploy code to staging or production
VCS có rất nhiều loại khác nhau, nhưng đều có đặc điểm chung là track history change of file/directory và loại được sử dụng nhiều nhất là Git
Distributed Version Control System
Git: Distributed Version Control System (DVCS).
Không giống như các hệ thống VCS sử dụng 1 server trung tâm, Git là sử dụng Distributed Architect, nghĩa là những người contributing 1 repository có thể có toàn bộ
copy của repository đó trên máy local của họ. Git không kết nối liên tục với central repository, Dev có thể làm việc ở bất kỳ đâu và collab một cách không đồng bộ
Tuy nhiên khi ta merge lại vào master branch ta cần phải update tất cả các snapshot mới nhất của nó, Git đảm bảo rằng chúng ta luôn ở version cuối cùng trước khi cho
người khác xem sự thay đổi của 1 repository.
Git thường được sử dụng để phát triển phần mềm mã nguồn mở và thương mại.
Repository
repository: Kho lưu trữ
Repository (repo) là một thư mục nằm ở trung tâm để lưu trữ tất cả file của bạn. Khi bạn tạo repository với các tệp và thư mục của mình, bạn có thể bắt đầu tracking
changes và versions.
Repository lưu giữ tất cả các commits, a snapshot of all your files at a point in time that have been made.
Snapshot
Trong computing:
• Snapshot có thể được định nghĩa là State của hệ thống tại một thời điểm cụ thể trong hệ thống máy tính.
• Nếu chúng ta thường xuyên chụp snapshot, mỗi thư mục hoặc tệp của chúng ta có thể được đưa trở lại trạng thái đó, nếu chúng ta bị nhiễm bất kỳ vi-rút nào, chỉ
cần Restore toàn bộ ổ đĩa, thư mục hoặc tệp về State trước khi bị nhiễm vi-rút.
Backup khác Versoning:
• Backup là toàn bộ bản copy của Data. Nếu một folder có 10GB data, nghĩa là file backup sẽ chiếm 10GB, và nếu cứ mỗi tiếng chúng ta backup 1 lần thì sau 10
tiếng chúng ta có 10 file backup 10GB.
• Snapshot chiếm một lượng nhỏ dung lượng đủ để ta khôi phục lại các thay đổi ở State này và trở lại State trước
Đặc điểm:
• Mỗi lần ta commit, 1 snapshot được tạo ra ghi lại tất cả state của project tại thời điểm đó.
• Tất cả các Snapshot là thứ tạo nên hisory của 1 project
• Snapshot sau đó sẽ được chứa trong Git Directory
HEAD
Khi làm việc với Git, chỉ một nhánh có thể được check tại một thời điểm - và đây được gọi là nhánh "HEAD". HEAD trỏ đến current checkout snapshot.
HEAD còn được coi là "current branch". Khi bạn chuyển đổi các branch với git checkout, HEAD sẽ thay đổi để trỏ đến đỉnh của branch mới.
Có thể coi HEAD là một bookmark để Git biết bạn đang ở đâu, cho dù bạn có nhiều repo, nhưng bạn vẫn có thể quay lại nơi bạn bookmarked
Commit Message
Commit Message giống như Clean Code, viết ngu sẽ không ai hiểu.
Một cấu trúc đơn giản nhất là:
Summarize changes in around 50 characters or less
Short Description ( Max 50 )
More detailed explanatory text, if necessary. Wrap it to about 72
characters or so.
Explain the problem that this commit is solving. Focus on why you
are making this change as opposed to how (the code explains that).
Are there side effects or other unintuitive consequences of this
change.
Detail Description ( Max 72 each line )
Further paragraphs come after blank lines.
- Bullet points are okay, too
- Typically a hyphen or asterisk is used for the bullet, preceded
by a single space, with blank lines in between, but conventions
vary here
If you use an issue tracker, put references to them at the bottom,
like this:
Resolves: #123
See also: #456, #789
Để xem được thông tin của commit
Commit ID
Commit ID:
-
40 characters được gọi là Hash
-
Hash được tạo ra bởi thuật toán encrypt gọi là SHA1
Tất cả thông tin trong commit:
-
Author
-
Date
-
Message
-
Snapshot
SHA1 Algorithm
string 40 characters
Tỷ lệ để xảy ra Collision là cực kỳ nhỏ và gần như không thể xảy ra
Branch
Về cơ chế:
Git Branch là một pointer đến snapshot, nó trỏ đến snapshot cuối cùng trong history.
Chúng ta có thể nói rằng các branch tạo ra một line of development tách biệt trong project. Bạn có thể tận dụng lợi thế của việc phân nhánh khi làm việc trên các tính
năng mới hoặc sửa lỗi vì nó tách biệt công việc của bạn với công việc của các thành viên khác trong nhóm.
Các nhánh khác nhau có thể được hợp nhất thành bất kỳ một nhánh nào miễn là chúng thuộc cùng một repo.
•
Default Branch mà Git tạo ra cho bạn là Master Branch, master branch không khác gì branch bình thường, tuy không bắt buộc nhưng thông thường Master Branch là
branch tốt nhất về trạng thái của dự án.
•
Trong thực tế, ta thường tạo một nhánh mới cho mỗi tác vụ (tức là một nhánh để sửa lỗi, một nhánh cho các tính năng mới, v.v.).
Đến đây, ta tự hỏi tại sao pointer lại gọi là branch ?
Nếu bạn thực hiện một số thay đổi và commit, nó sẽ lưu trữ một con trỏ đến commit ngay trước nó. Và vì thế series các snapshot trỏ vào nhau được gọi là branch ( vì nó
nhìn giống nhánh cây )
GIT LOCAL
Install GIT On Local PC
Step 1: Install HomeBrew
$ /bin/bash -c "$(curl -fsSL
https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
$ brew install git
Step 2: Install git
Config Git
Ta biết VSC track ai là người modify file, để làm được thì trước hết ta phải nói cho Git biết ta là ai.
$ git config --global user.email "tranthientrong.it@gmail.com"
Config Username & Email
$ git config --global user.name "trongkami"
--global để set cho tất cả repo
Xem Config
$ git config -l
Create Local Repository
Có 2 cách tạo repo:
1. Tạo repo riêng trên local
2. Hoặc clone để tạo copy của remote repo
$ git init
Step 1: Vào directory mình muốn
$ cd
Step 2: Biến directory đó thành reposity
$ git init
Bạn sẽ thấy một directory .git, đây được gọi là Git Directory:
• Khi chúng ta clone 1 repo, Git Directory cũng được copy vào local PC.
• Khu vực bên ngoài Git Directory được gọi là Working Tree, đây là version hiện tại của project của bạn
$ git add
Các file được đặt trong Working Tree không tự động được track bởi Git mà ta phải ra lệnh cho chúng
Yêu cầu Git track file
* file này chỉ trong working tree
Thêm tất cả file trong working tree vào Stage
$ git add <file name>
$ git add -A
Lúc này File được tracked sẽ vào Staging Area
$ git commit
Để commit tất cả change trong stage
$ git commit
Một màn hình hiện lên để ta nhập comment về commit này.
THÀNH CÔNG!!
Ta có thể dùng lệnh khác để add luôn comment
Để commit + comment
$ git commit -m "comment"
Git Workflow
Có ba thành phần chính của một dự án Git:
Repository
Repo là “vùng chứa” tất cả file trong dự án của bạn.
Working Tree
Working Tree bao gồm các tệp mà bạn hiện đang làm việc.
Staging - index
Đây là file ghi các thông tin về change, về file mới bị được commit. Index so sánh các tệp trong Working Tree với các tệp trong repo. Khi bạn
thực hiện một thay đổi trong Working Tree, index đánh dấu tệp là đã sửa đổi trước khi nó được commit.
$ git status
$ git status
Để biết thông tin về working tree và
những change trong stage
đây là thông tin trong stage area
$ git log --graph
Git có hổ trợ tính năng quá bá đó là illustrate hình ảnh GIT branch
Để Illustrate GIT branch
Hoặc khi bạn chỉ muốn nhìn thấy 1 dòng commit:
Tracking File
Tracked File là File đã có trong Snapshot
Sau khi File được tracked, nó có 3 states:
MODIFED ----> STAGED ----> COMMITED
$ git --graph
MODIFIED
STAGED
How To Track File
Yêu cầu Git track file
*chỉ trong working tree
$ git add <file name>
Chúng ta có thể xem file đã được track hay chưa?
Nếu track rồi thì đang ở đâu?
$ git status
Demo:
Ta thêm một file abc.txt vào Repo, lúc này file này chưa được track
1. MODIFED State
• Nếu file đã được track, mọi thay đổi trong file sẽ cho nó vào MODIFED
COMMITED
$ git status cho ta 3 thông tin:
- Ta đang trong Master brach
- file newFile đang trong MODIFIED
- file này đang không trong STAGED
•
2. STAGED Stage
$ git add
để file vào STAGED
$ git status cho ta 3 thông tin:
- Ta đang trong Master brach
- file newFile đang trong MODIFIED
- file này trong STAGED
•
3. COMMITED STATE
$ git commit để vào COMMITED
Lưu ý: Nó sẽ được snapshot trước khi vào Git Directory
Skipping Stage + Commit
Cho file vào Stage + Commit tất cả File đã được tracked
$ git commit -a
-a tương ứng với all
Sẽ dùng lệnh này thường xuyên vì không phải lúc nào cũng có thể stage, commit từng file
Demo: Thay đổi 2 file trong repo
Vì 2 file này đã được Track, ta có thể tiết kiệm thời gian vừa Stage + Commit cả 2 file cùng lúc
Get Information Of Change
$ git log
Để xem được những commit ta đã thực hiện
$ git log
$ git log -p
Để xem được thông tin chi tiết từng thay đổi trong mỗi commit
$ git log -p
comment của commit
file abc.txt
+ thông tin mới được thêm
- thông tin bị bỏ
$ git show
Chúng ta cũng có thể xem chi tiết của riêng 1 commit
Để xem được thông tin chi tiết từng của 1 commit
$ git show < commit id
>
$ git add -p
$ git add - p
Xem được những thay đổi trước khi vào STAGE
Nó sẽ hiện lên 1 dòng để ta chọn có STAGED những thay đổi này hay không
Stage this hunk ( y/n ) ?
Lệnh này cho phép chúng ta kiểm tra những thứ được thay đổi trước khi STAGED
Delete & Rename File
$ git rm
Remove file nghĩa là remove khỏi Git Directory + Working Tree luôn ( Untrack )
Về vật lý thì nó vẫn nằm trong directory đó chứ không vào trash. Nhưng nó sẽ không được nhận diện trong Git
Remove file khỏi Git Reposity
$ git rm < file name >
Lúc này file cũng vào STAGED, chúng ta phải commit để hoàn toàn remove file khỏi Git
Lúc này ta nhận ra 1 điều:
- add nghĩa là add vào Git Repo ( dù file đã trong Working Tree )
- rm nghĩa là remove khỏi Git Repo + Working Tree
$ git mv
Rename file
$ git mv [tên cũ] [tên mới]
Để ý sẽ lấy lệnh này giống với lệnh move, đúng vậy, bạn có thể dùng lệnh này để di chuyển file vào các
sub-directory trong working tree
Ignore .git file
Đối với những file được script tạo ra sẵn, rất khó chịu vì những file này không liên quan đến project, ví dụ như ở OSX luôn xuất hiện file.DS_Store
Ta không để xoá file đó đi ( vì nó sẽ được tạo lai ) mà phải Track 1 file ĐỐI NGHỊCH với file đó với đuôi là [tên file đó].gitignore
Step 1: Tạo file đối nghịch .gitignore
$ echo [tên file] > .gitignore
Step 2: Track File
$ git add .gitignore
Step 3: Commit File
$ git commit -m
Chưa ignore
Sau khi track file ignore
Undo
Reverse lại quá khứ là tính năng mạnh mẽ nhất của VSC.
UN-MODIFED git checkout
Từ checkout trong TA nghĩa là "Kiểm tra lại trước khi rời"
Chúng ta có thể hiểu là nó sẽ rời khỏi MODIFED. Để ta toàn quyền chỉnh sửa lại trước khi vào MODIFED lần nữa
Để rời khỏi MODIFED
$ git checkout [tên file]
Demo: Ta lỡ thêm những thứ ta không muốn, tuy nhiên ta đã ở trong MODIFED rồi, lúc này ta vẫn có thể ra
UN-STAGED git reset
Rời khỏi STAGE
$ git reset [tên file]
Như ta đã biết thì trong STAGE không chỉ có MODIFED mà còn có:
- new file ( track )
- renamed
- deleted
reset sẽ biến tất cả những thứ đó thành màu đỏ ( nghĩa là chưa được vô STAGE )
modified:
Ta lỡ cho file.txt vào STAGED
Ta cho file.txt ra khỏi STAGED,
trở về trạng thái lúc trước là
MODIFED
new file:
Ta lỡ Track file new.txt
Ta cho new.txt ra khỏi STAGE, trở
về trạng thái trước đó là Un-Track
renamed:
Ta lỡ đổi tên file.txt -> 123.txt
Ta cho 123.txt ra khỏi STAGE,
trở về trạng thái trước đó là file.txt
UN-COMMITED
git commit --amend
Lệnh này để Override Commit message
Để override commit message gần nhất
$ git commit --amend
git revert
Chúng ta có thể revert commit gần nhất sử dụng HEAD hoặc revert commit trong quá khứ sử dụng Commit ID
Để tạo commit mới revert lại commit gần nhất
$ git revert HEAD
Để bỏ lệnh revert
$ git revert --abort
HEAD Chúng ta dùng HEAD để xác định snapshot gần nhất ( aka commit )
Git reverse không phải là Ctrl + Z, mà là nó tạo ra một commit mới chứa lệnh trái ngược với commit trước đó.
Ví dụ:
Nếu commit gần nhất có stage là add
Thì trong reverse commit, nó sẽ có change là revert "add" -> Việc này giúp history của project consistent, ghi chép đúng những gì xảy ra.
Demo: Trong file của chúng ta có thứ phá hỏng mọi thứ và ta đã lỡ commit
Gõ $ git revert HEAD, editor hiện ra.
Chúng ta nên thêm Message vào để giải thích tại sao phải revert
Để ý bạn sẽ thấy cú pháp của câu lệnh commit và revert rất giống nhau, đương nhiên vì revert cũng chính là commit mà
Khi $ git log -p ra, ta sẽ thấy commit này
Để tạo commit mới revert lại commit trong quá
$ git revert [commit ID]
khứ
important: Hiện tại chỉ có thể reverst commit HEAD thôi, nếu muốn commit sâu hơn thì phải Merge hay gì đó, sẽ học sau
BRANCHING & MERGING
Xem Branch
Để xem có bao nhiêu branch
$ git branch
Lệnh git branch có thể create / delete / modify branch chứ không chỉ dừng lại ở đây.
Create Branch
Để tạo branch mới
$ git branch [tên branch mới]
Switch Branch
Để switch branch khác
$ git checkout [tên branch]
HEAD lúc này cũng nhảy sang branch mới
Thanks to ZSH mới biết gõ đang ở branch nào
$ git checkout -b
Tạo Branch mới + switch sang Branch đó
$ git checkout -b <branch name>
Giờ hãy thử tạo một commit trên branch này
Lúc này khi gọi $
git log -p ta thấy là HEAD đã chuyển đến current snapshot
Nhìn vào hình này, ta có thể illustrate GIT như sau:
Tất cả các commit sau đều tham chiếu đến commit trước, tuy nhiên chỉ cần 2 pointer là master và new_feature thì ta đã có thể hình dung ra được 2 branch mới
( đây trả lời cho câu hỏi tại sau pointer lại construct được thành branch )
commit 987a chính là nơi rẻ 2 nhánh.
Delete Branch
Delete Branch
*Không thể delete branch hiện tại đang ở
$ git branch -d <branch name>
important:
Chúng ta có thể dễ dàng delete 1 branch chưa có sự thay đổi nào, tuy nhiên nếu có sự thay đổi và chưa được merge vào master branch, git sẽ không delete liền
Merge Branchs
Để Merge Branch nào đó vào Branch hiện tại
$ git merge <branch name>
Un-Merge
$ git merge --abort
Sau khi merge, $
log -p bạn sẽ thấy:
( HEAD -> master, new_feature )
Như bạn đã biết, Branch thật chất là một references đến commit cuối. Vì thế khi merge 2 branch lại với nhau, 2
có nghĩa là gì.
pointer sẽ tham chiếu vào 1 commit, và HEAD đánh dấu bạn đang làm việc trên branch nào
Conflict
What cause Conflict
Git giúp việc hợp nhất trở nên cực kỳ dễ dàng. Hầu hết, Git sẽ tìm ra cách tự động tích hợp các thay đổi mới.
Tuy nhiên, xung đột thường nảy sinh khi hai người thay đổi các dòng giống nhau trong một file hoặc nếu một branch đã xóa file trong khi một branch khác đang
modify. Trong rường hợp này, Git không thể tự động xác định branch nào mới là chính xác ( không có prority giữa các branch kể cả master, cũng không có
synchronization giữa các branch )
Demo:
Ta sẽ sử đổi dòng "con meo" tại 2 branch:
• master
• new_feature
Switch to new_feature branch
Bây giờ 2 branch có commit bị conflict nhau ( cùng thay đổi line of code giống nhau )
Giờ ta merge lại với nhau:
Booommmm !
CONFLICT
Có thể dùng lệnh $ git status để kiểm tra tình trạng CONFLICT
Solve Conflict
Git đã add những comment trong file feature.txt, tuy nhiên chúng ta phải dùng editor mở file đó len
Mở File sử dụng VSCode
$ code [tên file]
Nếu muốn sử dụng cả 2, ta chỉ việc:
•
bỏ <<<<<<< HEAD
•
bỏ >>>>>>> new_feature
Giờ thì kiểm tra lại:
Git còn cho ta biết conflict fixed
Khi commit, trong commit message được GIT viết sẵn dòng "Merge branch"
GIT REMOTE
What is Git Hub:
Như ta đã biết Git là Distributed VCS, nghĩa là mỗi người có full copy của repo trên máy tính của họ.
Chúng ta có thể biến PC của mình thành server để host repo của mình và để người khác clone repo, lúc này repo của chúng ta là gọi là remote repo.
Tuy nhiên để thuận tiện, người ta thường đặt repo của mình lên một server chung và để người khác clone về. Một trong những Server chung đó là GitHub, GitHub là
Web-based remote repository hosting service for Git
Ngoài các tính năng chính của Git, GitHub cung cấp nhiều service khác.
Đầu tiên chúng ta cần hiểu là không có cách nào để link đồng bộ 2 Repository lại với nhau. Mà phải hiểu là:
-
Ta push LOCAL  REMOTE
-
Hoặc pull REMOTE  LOCAL
Create Remote Repo
Chỉ việc click new
Local to Remote
$ git remote add origin
Lệnh này tạo một remote mới được gọi là origin tại. Khi bạn làm điều
này, trong các lệnh push của mình, bạn có thể đẩy đến nguồn gốc
$ git remote add origin < git http >
( orifin ) thay vì phải nhập toàn bộ URL.
$ git push -u origin master
Lệnh push các commit trong nhánh LOCAL có tên là master đến
REMOTE có tên là origin
$ git push -u origin master
-u Để tạo copy branch từ local lên remote ( hay từ hoa mỹ gọi là upstream )
Lưu ý khi push lên bạn sẽ bị yêu cầu nhập Username và Password.
Password này không phải password tài khoản mà là Access Token lấy trong Github
$ git push
Bạn có thể dùng lệnh này khi đã upstream. ( xem cách upstream )
$ git push không phải là update cả local repo của ta lên remote repo mà nó sẽ gửi những commit ta thực hiện tại local trên remote repo, tất nhiên nếu trong
commit có add thêm file thì nó cũng update file lên luôn
Giờ ta muốn tất cả những thay đổi đó lên remote repo.
Update remote branch with local commit
$ git push
Demo: Ta tạo file.txt và push lên remote
Lưu ý: Ở LOCAL nếu chúng ta chưa update nội dung mới nhất ở REMOTE, thì push sẽ bị refected
Xem REMOTE
$ git remote -v
Ta có thể xem trạng thái của REMOTE
$ git remote -v
$ git remote show origin
Xem thông tin remote nhánh origin
$ git remote show origin
Demo: Tạo 1 file new trên remote
Tiếp theo gọi remote show origin
Dấu hiệu nhận biết có thông tin mới
Remote to Local
$ git clone
Ta có thể copy REMOTE về LOCAL, biến chúng thành local repo. ( lưu ý việc này không tạo nên mới liên hệ nào giữa LOCAL – REMOTE )
Để clone git từ GitHub về máy
$ git clone [URL]
Demo: Ta sẽ Clone JavaMultiThreading về Local
https://github.com/TranThienTrong/JavaMultithreading
Các bước để clone:
Step 1:
Copy URL
Step 2:
Clone về máy
mình
RESULT: Bây giờ chúng ta đã có local repo y chang remote repo
$ git pull
Khác vơi clone, pull dùng để chọn tuỳ branch mà bạn muốn merge vào
Để kéo nội dung từ branch bắt kỳ của REMOTE và merge vào branch hiện tại
$ git pull <URL> <branch>
URL đây là URL mà local repo clone về, thông thường người ta dùng origin, git sẽ tự hiểu
branch branch mà bạn muốn pull về
$ git pull thực hiện hai điều:
1. $ git fetch để tải content từ remote repo
2. $ git merge để merge remote content refs and heads into a new local merge commit.
Ví dụ, ta có 2 branch, local và remote
git pull sẽ tải xuống tất cả các thay đổi từ điểm mà local và remote bị chia ra. git pull sẽ fetch-tìm nạp các commit từ remote bị chia ra là A-B-C. Sau đó nó sẽ gọi
Merge với local brach.
Demo: Ta tạo remote_file.txt trong GitHub
Một 1 branch mới ở local repo, sau đó pull về
Update Remote Change
Như đã biết, GitHub cho chúng ta tính Synchronization, khi remote repo ta clone về bị thay đổi, thay vì lên web và xem lại ta có thể dùng.
$ git fetch
Fetch = tạo một Branch mới từ Remote
Tạo thêm branch từ REMOTE
Branch mới tên là origin/master
$ git fetch
$ git fetch sẽ downloads commits, files, và tất cả mọi thứ từ REMOTE -> LOCAL. Nó tạo 1 branch mới tên là origin/master để chứa các commit đó.
important: git fetch không merge vào local branch của bạn. Nó tạo ra các branch hiện có trong remote
Dùng $ git status sẽ cho ta biết ta đã OUTDATED from origin/master bao nhiêu commit
$ git merge origin
Merge origin/master branch
$ git merge origin
Lúc này local branh có thêm commit ( chưa cập nhật ) từ origin/master branch
GREAT!!
REMOTE BRANCHING
Remote Branch
Downstream
Khi sử dụng GIT, bạn đang " downstream hạ nguồn" khi bạn sao chép (clone, checkout, v.v.) từ một remote repo. Thông tin chảy "xuống hạ ngườn "
đến bạn.
Khi bạn thực hiện các thay đổi, bạn thường muốn gửi chúng trở lại "thượng nguồn" để chúng đưa nó vào kho lưu trữ đó để mọi người lấy từ cùng một
Upstream
nguồn đang làm việc với tất cả các thay đổi giống nhau.
Tại sao bạn nên thiết lập Upstream Branch cho Local Branch?
Giả sử current local HEAD branch hiện tại của bạn có tên là "feature". Khi bạn set "origin / feature" sẽ tạo ra mỗi quan hệ gọi là tracking. Mối quan hệ này rất hữu
ích vì hai lý do:
•
push và pull trở nên dễ dàng hơn rất nhiều. Với local branch, bạn có thể chỉ cần sử dụng các lệnh viết tắt "git pull" và "git push" - thay vì phải suy nghĩ về các
tham số chính xác như trong "git push origin feature" ( bạn phải checkout vào feature mới có thể gọi tắt )
•
Git hiện cũng có thể cho bạn biết về các commit chưa được đồng bộ hóa mà bạn chưa pull hoặc fetch về.
$ git push -u origin <branch>
Trước giờ ta chỉ học là push lên master (merge các local commit vào remote master ) nhưng trong thực tế ta chỉ nên push local branch của mình lên và đợi người khác
quyết định có merge hay không.
Để tạo copy branch từ local lên remote
$ git push -u orrigin <branch name>
-u Để tạo copy branch từ local lên remote ( hay từ hoa mỹ gọi là upstream )
[branch name] Bắt buộc phải cùng tên với branch local
Demo:
Ta đang làm việc với local branch tên là feature
Step 1:
Ta tạo feature.txt và
commit như bình thường
Step 2:
Ta tạo branch feature lên
remote repo luôn
Giờ thì trong Remote Repo xuất hiện luôn Branch Feature với file feature.txt
Còn branch Master vẫn bình thường
Lúc này feature branch tracking origin / feature branch
Khi gọi push hoặc pull ở master nó không phải ứng vì
nó chỉ tracking origin / master
Khi gọi push hoặc pull ở feature vì đã tracking rồi nên
nó tự động lên origin / feature
$ git push –delete origin
!important Lệnh này không delete local branch của bạn
Để delete remote branche
$ git push --delete origin [remote branch name]
Tracking / Copy Branch
$ git fetch
Fetching is what you do when you want to see what everybody else has been working on.
Tạo thêm branch từ remote repo
$ git fetch
$ git checkout origin/
Để copy 1 local branch và track remote branch
* Chúng sẽ có cùng tên, tuy nhiên remote branch sẽ có
prefix là origon/
$ git fetch
$ git checkout origin/[tên remote branch]
A 'tracking branch' in Git is a local branch that is connected to a remote branch. When you push and pull on that branch, it automatically pushes and pulls to the remote
branch that it is connected with.
Khi bạn clone một remote repo, nó thường tự động cho master branch để track origin/master. Đó là lý do tại sao git push và git pull hoạt động hiệu quả mà không có
arguments nào khác. Tuy nhiên, bạn có thể thiết lập các tracking branches khác nếu muốn
ĐẶC BIỆT: Khi bạn track branch cũng có nghĩa là bạn tạo 1 local branch có TẤT CẢ NỘI DUNG của remote branch này
Demo: Đầu tiên ta tạo branch hello tạo remote
$ git remote show origin cũng cho ta biết hello branch là new và chưa được track
Step 1
Bắt buộc phải gọi $ git fetch, lúc đó mới track được
Step 2
$ git checkout branch đó
Giờ thì origon/hello đã được tracked
Ta có thể thấy branch hello trong local
$ git remote update
Để fetch tất cả các branch trong remote repo, ta có thể gọi lệnh này, còn việc có merge nó hay không tuỳ thuộc vào bạn
Demo: Tạo 3 branches mới trên GitHub
Fetch cả 3.
$ git rebase
!important lệnh này không thay thế merge mà nó làm cách merge dễ nhìn và debug hơn
$ checkout [current branch]
Để thay đổi base của [current branch]
Git merge adds a new commit, preserving the history.
$ git rebase [base branch]
Git rebase moves a feature branch into a master
Để đơn giản nhất thì bạn --graph ra
Như bạn thấy feature branch và master branch rất lộn xộn, nếu merge vào rất khó nhìn. trong khi feature chỉ có 3 commits là khác master
WALLA
Lưu ý, có thấy vẫn có master và feature không, vì chúng vẫn đang là 2 branch riêng lẻ, chưa merge với nhau.
Chúng ta dùng $ git rebase để biến 3-ways thành fast-forward merge
!important Git Rebase sẽ báo Conflict dù ta chưa Merge. Cách xử lý thì vẫn là mở Editor thôi
SOLVING CONFLICT
Conflict with remote commit
• Thông thường CONFLICT chỉ xảy ra ở Git Pull.
• Không phải vì Git Push không xảy ra CONFLICT, mà vì GIT yêu cầu ta luôn có phiên bản mới nhất của remote repo trước khi push, nên commit ta push lên luôn là
cuối cùng và dễ dàng fast-forward merge. Tất nhiên thì nếu ta push lên 1 branch A, người khác ở 1 branch B, khi merge lại vẫn có thể CONFLICT như thường
Ở remote nếu chúng ta chưa update nội dung mới ở remote, thì push sẽ bị refected
Để có thể update, ta phải dùng $ git pull
Tuy nhiên nếu ta pull xuống thì commit bị CONFLICT với commit gần nhất của ta thì sau ( điều kiện để CONFLICT vẫn như local )
git graph ra thì ta sẽ thấy branch hiện tại ( local master ) không thể merge với origin/master
Nhìn vào hình này, ta có được 2 thông tin
1. local branch chưa update và push không có hiệu lực
2. commit cuối của local branch và commit cuối của origin/master CONFLICT với nhau
Resolve Conflict
Giống như ở Local Branch, ta giải quyết conflict bằng việc mở editor
Mở File sử dụng VSCode
$ code [tên file]
Nếu muốn sử dụng cả 2, ta chỉ việc:
•
bỏ <<<<<<< HEAD
•
bỏ >>>>>>>
Giờ chúng ta cứ commit như bình thường là merge thành công từ pull, đồng thời pull sẽ update branch của ta nên ta có thể push luôn
THÀNH CÔNG, THÀNH CÔNG, ĐẠI THÀNH CÔNG
COLLABORATION
Best Practice
1
Luôn synchronize local branch trước khi bắt đầu việc gì đó
2
Good commit message very important
Tránh 1 commit thay đổi nhiều thứ
1 commit chỉ nên làm 1 việc:
3
4
•
rename
•
fix
•
add feature
•
delete
•
Nên có một branch phụ về các feature
•
Và nhớ thường xuyên merge từ master về feature, để tránh nhiều sự CONFLICT khi merge lại trong master
Master là branch chứa phiên bản mới nhất
5
6
Nhưng phiên bản stable nhất nên để 1 branch riêng
Rebase sẽ làm thay đổi commit ID, vì thế không nên rebase change sẽ push lên remote repo
Pull Request
Fork & Pull Request
GitHub fork là một bản copy của repo nằm trong account của bạn chứ không phải account mà bạn đã fork-tách dữ liệu từ đó. Sau khi fork một repo, bạn sở hữu forked
copy. Nghĩa là bạn có thể chỉnh sửa nội dung của fork repo của mình mà không ảnh hưởng đến repo chính.
Vậy sự khác nhau giữ fork và clone là gì?
Khi bạn nói rằng bạn đang Forking repo, về cơ bản, bạn đang tạo một bản cpoy của origin repo sử dụng ID GitHub của mình. Điểm chính cần lưu ý ở đây là bất kỳ thay
đổi nào được thực hiện đối với origin repo sẽ được phản ánh trở lại Fork Repo của bạn (bạn cần fetch và merge). Tuy nhiên, nếu bạn thực hiện bất kỳ thay đổi nào đối
với Fork Repo của mình, bạn sẽ phải tạo một Pull Request đến origin repo. Nếu origin repo của bạn được admin của origin repo chấp thuận, thì các thay đổi của bạn sẽ
được commit / merge với origin repo.
Mặt khác, các thay đổi được thực hiện trên cloned repository có thể được đẩy trực tiếp upstream repository sử dụng push mà không cần hỏi người sở hữu repo đó. Đối
với điều này, người dùng phải có quyền WRITE. Nếu người dùng không có quyền WRITE, cách duy nhất để thực hiện là thông qua fork request. Trong trường hợp đó,
các thay đổi được thực hiện trong cloned repo trước tiên được push đến forked repository và sau đó một pull request được tạo.
It is a better option to fork before clone if the user is not declared as a contributor and it is a third party repository (not of the organization).
Demo:
Step 1:
Tìm 1 repo không phải của mình
Click Fork
Step 2:
Đây là giao diện của Fork Repo của mình.
Có chữ forked from origin repo
Step 3:
Thay đổi file trong fork repo
Step 4:
Có 2 lựa chọn:
1. commit vào master branch của FORK repo
2. Tạo branch với tên TranThienTrong-patch-1 và Pull
Request
Step 5:
•
Giao diện commit trong TranThienTrong-patch-1
branch.
•
Click Create Pull Request
Clone The Fork Repo
Ở ví dụ trước, ta đã Fork Repo về, giờ ta sẽ clone nó
Demo: Ta sẽ tạo 1 file và push lên fork remote, với branch là origin/trong
Đây là giao diện của GitHub khi tạo Pull Request.
Lưu ý là Fork Repo và Pull Request không phải chức năng gốc của Git, vì thế ta không làm trên Terminal được, nhưng hầu hết GitLab, GitBucket... đều có chức năng
này.
Sau khi Create Pull Request, ta tạo ra 1 pull request
Edit Pull Request
Một project có tab riêng để chứa các Pull Request, và đồng nghiệp hoặc chủ origon repo có thể vào comment để sửa, đó là lúc ta cần chức năng update thay vì lại tạo
mới
Ta sẽ push commit mới lên fork repo của chúng ta
Lúc này ở tab
tự động xuất hiện commit này, chứng tỏ là Git tự nhận diện trong branch là banch mà ta muốn merge với origin.
Và thật ra, nếu ta muốn tạo 1 pull request riêng cho commit này, ta phải tạo 1 branch mới, chứng tỏ Git đã bắt buộc Branch này phải là Branch trong Pull Request ->
Pull Request là một yêu cầu Merge Branch hơn là yêu cầu về commit
Squashing Commit
git base -i [branch]
Nếu chúng ta có quá nhiều thay đổi, 5-6 commit nhưng giờ chúng ta chỉ giữ lại 1 commit thì sao
Lúc này chúng ta sử dụng Rebase, tuy nhiên Rebase có rất nhiều loại, để biết sử dụng loại nào, ta thêm -i
$ checkout [current branch]
Để thay đổi base của [current branch]
-i để mở ra interactive rebase
$ git rebase -i [base branch]
step 1:
gõ lệnh
step 2:
Mặc định khi rebase chúng ta dùng 'pick' nghĩa là sử
dụng cả 2 commit
step 3:
Sử dụng squash cho commit thứ 2
Squash giúp chúng ta sử dụng chức năng của commit
này nhưng hợp nó lại với commit trước đó.
step 4
Cửa sổ hiện lên để ta gõ commit message
THÀNH CÔNG:
Giờ thì trong lịch sử chỉ còn 1 commit
git push -f
Để ép việc push lên branch của pull request
$ git push -f
Vì branch sử dụng để pull request là của mình, vì thế cứ việc force push thoải mái, nhưng ko được dùng
với public branch
Nhưng, tại sao chuyện này lại xảy ra được, trong thực tế không thể nào thay đổi commit. Đây là thực tế, 2 lệnh commit kia vẫn còn đó, tuy nhiên ta chỉ tạo ra một
commit mới có chức năng ( pick commit 1, squash commit 2) mà thôi
Ta không thể push bình thường mà phải force forward sử dụng git push -f
Giờ thì xem, không còn phân nhánh nữa, tất cả chỉ có 1 commit mà thôi
Code Review
Trong tab File changed, bạn có thể thêm comment vào
Review tổng thể
chỉ dành cho chủ origin
Review code:
Sau khi thêm review:
PRACTICE
Upload whole local repo to remote repo
Create Local Repo
1. Initialize the local directory as a Git repository.
$ git init
2. Stages add file
$git add -A
3. Commit all
$ git commit -m
Create & Clone empty remote Repo
1. Create a new repository on GitHub. To avoid errors, do not initialize the new repository with README, license, or gitignore files.
2. Clone remote repo
Stage Remote Repo
3. Push to remote repo
DONE!!!
Download