Xóa tất cả các nhánh git cục bộ


323

Tôi theo một quy trình phát triển nơi tôi tạo một chi nhánh địa phương mới cho mỗi tính năng hoặc thẻ câu chuyện mới. Khi hoàn thành tôi hợp nhất nhánh thành chủ rồi đẩy.

Điều có xu hướng xảy ra theo thời gian do sự kết hợp của sự lười biếng hoặc quên lãng, là tôi kết thúc với một danh sách lớn các chi nhánh địa phương, một số trong đó (chẳng hạn như gai) có thể không được hợp nhất.

Tôi biết làm thế nào để liệt kê tất cả các chi nhánh địa phương của tôi và tôi biết làm thế nào để loại bỏ một chi nhánh duy nhất nhưng tôi đã tự hỏi nếu có một lệnh git cho phép tôi xóa tất cả các chi nhánh địa phương của tôi?

Dưới đây là đầu ra của git branch --mergedlệnh.

user@machine:~/projects/application[master]$ git branch --merged
  STORY-123-Short-Description
  STORY-456-Another-Description
  STORY-789-Blah-Blah
* master

Tất cả các nỗ lực để xóa các nhánh được liệt kê với grep -v \*(theo các câu trả lời dưới đây) đều dẫn đến lỗi:

error: branch 'STORY-123-Short-Description' not found.
error: branch 'STORY-456-Another-Description' not found.
error: branch 'STORY-789-Blah-Blah' not found.

Tôi đang sử dụng:
git 1.7.4.1 ub
Ubuntu 10.04
GNU bash, phiên bản 4.1.5 (1) - phát hành
GNU grep 2.5.4


7
Tôi xin bạn chấp nhận câu trả lời của @Andrew!
Robert Siemer


@GiulioCaccin Câu hỏi cũng liên quan đến các nhánh có thể chưa được hợp nhất và tôi đã cập nhật câu hỏi để phản ánh rõ ràng điều này.
Louth

Câu trả lời:


384

Tiểu ban 'git chi nhánh -d' có thể xóa nhiều hơn một chi nhánh. Vì vậy, đơn giản hóa câu trả lời của @ sblom nhưng thêm một xargs quan trọng:

git branch -D `git branch --merged | grep -v \* | xargs`

hoặc, đơn giản hóa hơn nữa để:

git branch --merged | grep -v \* | xargs git branch -D 

Điều quan trọng, như được ghi nhận bởi @AndrewC, bằng cách sử dụng git branch cho kịch bản là không được khuyến khích. Để tránh nó sử dụng một cái gì đó như:

git for-each-ref --format '%(refname:short)' refs/heads | grep -v master | xargs git branch -D

Thận trọng khi xóa!

$ mkdir br
$ cd br; git init
Initialized empty Git repository in /Users/ebg/test/br/.git/
$ touch README; git add README; git commit -m 'First commit'
[master (root-commit) 1d738b5] First commit
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README
$ git branch Story-123-a
$ git branch Story-123-b
$ git branch Story-123-c
$ git branch --merged
  Story-123-a
  Story-123-b
  Story-123-c
* master
$ git branch --merged | grep -v \* | xargs
Story-123-a Story-123-b Story-123-c
$ git branch --merged | grep -v \* | xargs git branch -D
Deleted branch Story-123-a (was 1d738b5).
Deleted branch Story-123-b (was 1d738b5).
Deleted branch Story-123-c (was 1d738b5).

Lệnh này vẫn báo cáo các lỗi tương tự như được đề cập trong các ý kiến ​​cho câu trả lời dưới đây. error:branch 'STORY-123-Short-Description' not found.cho mỗi ngành được liệt kê.
Louth

1
Làm việc cho tôi; xem ở trên với các chi tiết được thêm vào.
GoZoner

1
Vì vậy, việc sử dụng git 1.7.10 có giải quyết được vấn đề của bạn hay bạn thích làm việc trực tiếp trong kho .git?
GoZoner

1
Nếu bạn gặp error:branch 'STORY-123-Short-Description' not found.lỗi, điều này có thể là do cài đặt màu git. Điều này làm việc cho tôi (lưu ý --no-colortùy chọn):git branch --no-color --merged | grep -v \* | xargs git branch -D
marcok

3
Câu trả lời duy nhất trên SO tôi thấy rằng nó hoạt động. Cảm ơn bạn!
Kevin Scos

140

Tôi đã tìm thấy một cách đẹp hơn trong một nhận xét về vấn đề này trên github :

git branch --merged master --no-color | grep -v master | grep -v stable | xargs git branch -d

chỉnh sửa: thêm tùy chọn không màu và loại trừ nhánh ổn định (thêm các nhánh khác nếu cần trong trường hợp của bạn)


2
Cuối cùng, giải pháp tôi đang cần
Code Whisperer

1
Tôi đã thử điều này nhưng tiếp tục nhận được error: branch 'my-branch-name' not found.cho mọi chi nhánh. Sử dụng phiên bản git 1.8.3.4 (Apple Git-47). Bất cứ ý tưởng tại sao?
đâu đó

thử 'git chi nhánh - tổng hợp chủ | grep -v chủ | xargs echo 'để gỡ lỗi chính xác những gì nó đang cố gắng xóa? không có ý tưởng nào tốt hơn ...
mBardos

2
Vì thế. git for-each-ref --format '%(refname:short)' refs/heads/ | grep -v master | xargs git branch -d
Hôm nay 26/8/2015

1
Sử dụng xargs sử dụng cùng với điều này. Cảm ơn
Volem

105

Phân tích đầu ra của git branchkhông được khuyến nghị và không phải là một câu trả lời tốt cho các độc giả tương lai trên Stack Overflow.

  1. git branchlà những gì được gọi là một lệnh sứ. Các lệnh sứ không được thiết kế để được phân tích cú pháp máy và đầu ra có thể thay đổi giữa các phiên bản Git khác nhau.
  2. Có các tùy chọn cấu hình người dùng thay đổi đầu ra git branchtheo cách gây khó khăn cho việc phân tích cú pháp (ví dụ: tô màu). Nếu người dùng đã thiết lập color.branchthì bạn sẽ nhận được mã điều khiển ở đầu ra, điều này sẽ dẫn đến error: branch 'foo' not found.nếu bạn cố chuyển nó thành một lệnh khác. Bạn có thể bỏ qua điều này với --no-colorcờ đến git branch, nhưng ai biết cấu hình người dùng khác có thể phá vỡ mọi thứ.
  3. git branch có thể làm những việc khác gây khó chịu khi phân tích cú pháp, như đặt dấu hoa thị bên cạnh nhánh đang được kiểm tra

Người duy trì git có điều này để nói về kịch bản xung quanh git branchđầu ra

Để tìm hiểu chi nhánh hiện tại là gì, người dùng bình thường / bất cẩn có thể đã viết kịch bản xung quanh chi nhánh git, điều này là sai. Chúng tôi chủ động không khuyến khích sử dụng bất kỳ lệnh Sứ nào, kể cả nhánh git, trong các tập lệnh, vì đầu ra từ lệnh có thể thay đổi để giúp trường hợp sử dụng của con người.

Câu trả lời đề xuất chỉnh sửa thủ công các tệp trong .git thư mục (như .git / refs / Heads) cũng có vấn đề tương tự (thay vào đó, ref có thể ở dạng .git / pack-refs hoặc Git có thể thay đổi bố cục bên trong của chúng trong tương lai).

Git cung cấp for-each-ref lệnh để lấy danh sách các nhánh.

Git 2.7.X sẽ giới thiệu --mergedtùy chọn để bạn có thể làm một cái gì đó như bên dưới để tìm và xóa tất cả các nhánh được hợp nhất vàoHEAD

for mergedBranch in $(git for-each-ref --format '%(refname:short)' --merged HEAD refs/heads/)
do
    git branch -d ${mergedBranch}
done

Git 2.6.X trở lên, bạn sẽ cần liệt kê tất cả các nhánh cục bộ và sau đó kiểm tra chúng riêng lẻ để xem chúng có được hợp nhất không (sẽ chậm hơn đáng kể và phức tạp hơn một chút).

for branch in $(git for-each-ref --format '%(refname:short)' refs/heads/)
do
    git merge-base --is-ancestor ${branch} HEAD && git branch -d ${branch}
done

git branch --no-color 2>/dev/null?
tộc

5
Đó là một sự cải tiến chắc chắn. Bạn sẽ luôn gặp phải vấn đề cần lọc *, và sẽ rất thú vị nếu ai đó chạy nó từ đầu tách ra. Vấn đề chính là git branchlệnh sứ và không có gì đảm bảo rằng đầu ra sẽ không thay đổi trong một số phiên bản git trong tương lai.
Andrew C

Cảm ơn bạn @AndrewC - đây là cả hai câu trả lời cho câu hỏi về lỗi "không tìm thấy nhánh" bí ẩn và cung cấp giải pháp làm việc bằng cách sử dụng lệnh thích hợp hơn! 👍
Jason

2
Các lệnh GIT 'Sứ' và 'không sứ' được xác định như thế nào?
GoZoner

1
Có lẽ sẽ là một cải tiến hữu ích để loại trừ 'dev' và 'master' theo mặc định?
PandaWood

66

Cách đơn giản hơn để xóa tất cả các nhánh nhưng giữ cho các nhánh khác như "phát triển" và "chính" là như sau:

git branch | grep -v "develop" | grep -v "master" | xargs git branch -D

rất hữu ích !


8
Bạn đã hồi sinh một chủ đề lâu đời và đăng một câu trả lời gần như giống hệt với một chủ đề hiện có, đó là lỗi và thiếu các thay đổi an toàn mà nó có. Đây không phải là một câu trả lời tốt.
Andrew C

6
Câu trả lời này là rõ ràng trong đầu ra đường ống từ nhánh git, sửa đổi nó và chuyển đến nhánh git -D. Không cần phải có ý nghĩa.
Pam

Giải pháp này đã làm việc cho tôi. Xóa tất cả các chi nhánh địa phương.
Prad

1
Điều này sẽ không xóa bất kỳ nhánh nào chứa từ phát triển hoặc chủ như 'Develop_feature' hoặc 'master_feature'.
django

ĐÂY LÀ TRẢ LỜI TÔI ĐANG TÌM KIẾM
Konrad G

62

Để xóa mọi chi nhánh ngoại trừ chi nhánh mà bạn hiện đã kiểm tra:

for b in `git branch --merged | grep -v \*`; do git branch -D $b; done

Tôi sẽ khuyên bạn nên thay đổi git branch -D $bmột echo $bvài lần đầu tiên để đảm bảo rằng nó sẽ xóa các nhánh mà bạn dự định.


1
với lệnh này tôi nhận được error:branch 'a_branch_name' not found.Tôi có thể thấy những gì bạn đang cố gắng thực hiện và tôi đã chơi xung quanh với lệnh nhưng vì lý do nào đó git dường như không thích các tên chi nhánh được cung cấp ...
Louth

hừm để giúp khắc phục sự cố, sẽ hữu ích khi xem một số ví dụ đầu ra từgit branch --merged
sblom

tên chi nhánh của tôi có định dạngSTORY-123-Short-Description
Louth

và khi bạn chạy git branch --merged, bạn có nhận được một danh sách với một trong những người trên mỗi dòng không?
sblom

1
nó có nghĩa đen error:branch 'a_branch_name' not found.không? Hoặc nó phàn nàn về một trong những tên chi nhánh từ git branchđầu ra của bạn ở trên?
sblom

52

Lệnh dưới đây sẽ xóa tất cả các nhánh cục bộ trừ nhánh chính.

git branch | grep -v "master" | xargs git branch -D

Lệnh trên

  1. liệt kê tất cả các chi nhánh
  2. Từ danh sách bỏ qua nhánh chính và lấy phần còn lại của nhánh
  3. xóa chi nhánh

4
Tôi sẽ sử dụng git branch | grep -v "master" | xargs git branch -dđầu tiên để tôi không xóa các nhánh chưa được trộn, chỉ để an toàn. Nhưng câu trả lời tốt đẹp!
Jonas Lomkeept

3
Đây là phiên bản quyền hạn,@(git branch | Select-String -Pattern "[^(*?)\s? master]") | ForEach-Object{$_.Line.Trim()} | %{git branch -D $_}
Jonas Lomkeept

1
@baklazan điều này sẽ chỉ hoạt động trong dòng lệnh Windows 10 nếu bạn đã cài đặt một số công cụ. Bạn có thể có MINGW hoặc một số thứ khác như vậy và bạn không biết điều đó.
KthProg

42

Chỉ cần một lưu ý, tôi sẽ nâng cấp lên git 1.7.10. Bạn có thể nhận được câu trả lời ở đây sẽ không hoạt động trên phiên bản của bạn. Tôi đoán là bạn sẽ phải đặt tiền tố tên chi nhánh với refs/heads/.

THẬN TRỌNG, chỉ tiến hành những điều sau nếu bạn tạo một bản sao của thư mục làm việc và thư mục .git.

Đôi khi tôi chỉ đi trước và xóa các nhánh tôi không muốn đi thẳng .git/refs/heads. Tất cả các nhánh này là các tệp văn bản chứa 40 ký tự sha-1 của cam kết mà chúng trỏ tới. Bạn sẽ có thông tin không liên quan .git/confignếu bạn có thiết lập theo dõi cụ thể cho bất kỳ ai trong số họ. Bạn có thể xóa các mục đó bằng tay là tốt.


Cuối cùng là một lựa chọn đơn giản và thực dụng. Tôi thích nó: D
Melvyn

2
Điều này sẽ không hoạt động nếu bạn đã đóng gói refs, hoặc thậm chí nếu bạn nhân bản từ máy chủ từ xa đôi khi (sẽ cung cấp cho bạn các tệp được đóng gói). Nếu bạn giới thiệu được đóng gói, thì các ref sẽ không được lưu trữ trong .git / refs / Heads, chúng sẽ được lưu trữ trong một tệp có tên là "pack-refs". Xem git-scm.com/docs/git-pack-refs .
Alexander Bird

1
Có vẻ như là một ý tưởng tồi để loại bỏ chi nhánh mà bạn đã kiểm tra tại thời điểm này
Moberg

@Moberg Chỉ cần kiểm tra một cam kết trước đó, và ĐẦU của bạn sẽ nổi lên.
RomainValeri

34

Hãy thử lệnh shell sau:

git branch | grep -v "master" | xargs git branch -D

Giải trình:

  • Nhận tất cả các chi nhánh thông qua git branch | grep -v "master" lệnh
  • Chọn mỗi nhánh bằng xargslệnh
  • Xóa chi nhánh với xargs git branch -D

3
Mặc dù đây có thể là một câu trả lời đúng. Một dòng mã không hữu ích nếu không có lời giải thích về điều gì và cách giải quyết câu hỏi ban đầu. Vui lòng cung cấp chi tiết cho câu trả lời của bạn.
RyanNerd

28

Để xóa tất cả các nhánh cục bộ trong linux ngoại trừ nhánh bạn đang bật

// hard delete

git branch -D $(git branch)

2
Điều này cảm thấy an toàn hơn là đi vào .git và loại bỏ công cụ.
nelsontruran

25

Tôi thấy dễ dàng hơn khi chỉ sử dụng trình soạn thảo văn bản và trình bao.

  1. Nhập git checkout <TAB>vỏ. Sẽ hiển thị tất cả các chi nhánh địa phương.
  2. Sao chép chúng vào một trình soạn thảo văn bản, loại bỏ những thứ bạn cần giữ.
  3. Thay thế ngắt dòng bằng dấu cách. (Trong SublimeText, nó siêu dễ.)
  4. Mở vỏ, gõ git branch -D <PASTE THE BRANCHES NAMES HERE>.

Đó là nó.


Tôi không nghĩ bạn có thể loại bỏ chi nhánh mà bạn đang đứng.
Đồng Thắng

@Dong Có * bên cạnh chi nhánh đó nên bạn chỉ cần xóa nó khỏi danh sách đã sao chép!
Melanie

12

Tôi đã có một loại tình huống tương tự và gần đây thấy lệnh sau hữu ích.

git branch -D `git branch | awk '{ if ($0 !~ /<Branch_You_Want_to_Keep>/) printf "%s", $0 }'`

Nếu bạn muốn giữ nhiều chi nhánh, thì

git branch -D `git branch | awk '{ if ($0 !~ /<Branch_You_Want_to_Keep1>|<Branch_You_Want_to_Keep2>/) printf "%s", $0 }'`

hy vọng điều này sẽ giúp ai đó.


1
Đẹp một nhưng tôi cần backticks để làm cho nó hoạt động - git branch -D `git branch | awk '{ if ($0 !~ /master/) printf "%s", $0 }'` Thực tế tôi nghĩ rằng bạn đã có chúng ban đầu nhưng họ đã bị mất trong định dạng SO.
tassinari

10

Từ Windows Command Line, xóa tất cả ngoại trừ nhánh đã kiểm tra hiện tại bằng cách sử dụng:

for /f "tokens=*" %f in ('git branch ^| find /v "*"') do git branch -D %f

7

Nếu bạn không cần phải tự đi qua Git, bạn cũng có thể xóa các đầu dưới .git / refs / thủ công hoặc lập trình. Sau đây sẽ hoạt động với tinh chỉnh tối thiểu theo Bash:

shopt -s extglob
rm -rf .git/refs/heads/!(master)

Điều này sẽ xóa mọi chi nhánh địa phương trừ chi nhánh chính của bạn. Vì các nhánh ngược dòng của bạn được lưu trữ dưới .git / refs / điều khiển từ xa , nên chúng sẽ không bị ảnh hưởng.

Nếu bạn không sử dụng Bash hoặc muốn truy xuất nhiều kho Git cùng một lúc, bạn có thể làm điều gì đó tương tự với GNU find:

find . \
    -path remotes -path logs -prune -o \
    -wholename \*.git/refs/heads/\* \! -name master -print0 |
xargs -0 rm -rf

Giải pháp tìm kiếm có thể dễ mang theo hơn, nhưng việc cắt xén các đường dẫn và tên tệp là khó khăn và có khả năng dễ bị lỗi hơn.


Mát mẻ. Xóa hình ảnh :)
Sandfish

5

Không có câu trả lời nào thỏa mãn đầy đủ nhu cầu của tôi, vì vậy chúng tôi đi đây:

git branch --merged | grep -E "(feature|bugfix|hotfix)/" | xargs git branch -D && git remote prune origin

Điều này sẽ xóa tất cả các chi nhánh địa phương được hợp nhất và bắt đầu với feature/, bugfix/hoặc hotfix/. Sau đó, điều khiển từ xa ngược dòngorigin được cắt tỉa (bạn có thể phải nhập mật khẩu).

Hoạt động trên Git 1.9.5.


5

Dựa trên sự kết hợp của một số câu trả lời ở đây - nếu bạn muốn giữ tất cả các nhánh tồn tại trên điều khiển từ xa nhưng xóa phần còn lại , thì oneliner sau đây sẽ thực hiện thủ thuật:

git for-each-ref --format '%(refname:short)' refs/heads | grep -Ev `git ls-remote --quiet --heads origin | awk '{print substr($2, 12)}'| paste -sd "|" -` | xargs git branch -D

3

Mặc dù đây không phải là giải pháp dòng lệnh, tôi ngạc nhiên khi GUI Git chưa được đề xuất.

Tôi sử dụng dòng lệnh 99% thời gian, nhưng trong trường hợp này, nó sẽ chậm lại (do đó là câu hỏi ban đầu) hoặc bạn không biết mình sắp xóa gì khi sử dụng một số thao tác vỏ thông minh nhưng dài.

Giao diện người dùng giải quyết vấn đề này vì bạn có thể nhanh chóng kiểm tra các nhánh bạn muốn xóa và được nhắc nhở về các nhánh bạn muốn giữ mà không phải gõ lệnh cho mỗi nhánh.

Từ giao diện người dùng đi đến Chi nhánh -> XóaCtrl + Nhấp vào các nhánh bạn muốn xóa để chúng được tô sáng. Nếu bạn muốn chắc chắn rằng chúng được hợp nhất thành một nhánh (chẳng hạn như dev), bên dưới Xóa Chỉ khi được hợp nhất đặt Chi nhánh địa phương thành dev. Nếu không, đặt thành Luôn luôn để bỏ qua kiểm tra này.

GitUI: xóa các chi nhánh địa phương


1

Đối với powershell, điều này sẽ hoạt động:

git branch --format '%(refname:lstrip=2)' --merged `
    | Where-Object { $_ -ne 'master' } `
    | ForEach-Object { git branch -d $_ }

0

Kịch bản sau đây xóa các nhánh. Sử dụng nó và sửa đổi nó có nguy cơ của riêng bạn, vv

Dựa trên các câu trả lời khác trong câu hỏi này, cuối cùng tôi đã viết một kịch bản bash nhanh cho chính mình. Tôi gọi nó là "gitbd" (git chi nhánh -D) nhưng nếu bạn sử dụng nó, bạn có thể đổi tên nó thành bất cứ điều gì bạn muốn.

gitbd() {
if [ $# -le 1 ]
  then
    local branches_to_delete=`git for-each-ref --format '%(refname:short)' refs/heads/ | grep "$1"`
    printf "Matching branches:\n\n$branches_to_delete\n\nDelete? [Y/n] "
    read -n 1 -r # Immediately continue after getting 1 keypress
    echo # Move to a new line
    if [[ ! $REPLY == 'N' && ! $REPLY == 'n' ]]
      then
        echo $branches_to_delete | xargs git branch -D
    fi
else
  echo "This command takes one arg (match pattern) or no args (match all)"
fi
}

Nó sẽ đề nghị xóa bất kỳ nhánh nào khớp với một đối số mẫu, nếu được truyền vào hoặc tất cả các nhánh cục bộ khi được gọi mà không có đối số. Nó cũng sẽ cung cấp cho bạn một bước xác nhận, vì, bạn biết đấy, chúng tôi đang xóa mọi thứ, vì vậy điều đó thật tuyệt.

Thật là ngu ngốc - nếu không có các nhánh phù hợp với mô hình, nó sẽ không nhận ra nó.

Một ví dụ đầu ra chạy:

$ gitbd test
Matching branches:

dummy+test1
dummy+test2
dummy+test3

Delete? [Y/n] 

0

Tôi đã viết một kịch bản shell để xóa tất cả các nhánh cục bộ ngoại trừ develop

branches=$(git branch | tr -d " *")
output=""
for branch in $branches 
do
  if [[ $branch != "develop" ]]; then
    output="$output $branch"
  fi
done
git branch -d $output

0

Trên câu trả lời hoạt động tốt. Đây là một cách tiếp cận khác khi chúng tôi có rất nhiều chi nhánh trong repo cục bộ và chúng tôi phải xóa nhiều chi nhánh trừ một số ít nằm trong máy cục bộ.

Đầu tiên git branchsẽ liệt kê tất cả các chi nhánh địa phương.

Để hoán chuyển cột tên nhánh thành một hàng trong tệp bằng cách chạy lệnh unix
git branch > sample.txt
Điều này sẽ lưu nó trong tệp sample.txt . Và chạy
awk 'BEGIN { ORS = " " } { print }' sample.txt
lệnh trong shell. Điều này sẽ chuyển đổi cột thành hàng và sao chép danh sách các tên nhánh trong một hàng.

Rồi chạy
git branch -D branch_name(s).
Điều này sẽ xóa tất cả các chi nhánh được liệt kê có mặt tại địa phương


0

Cách thực tế nhất: đảm bảo bạn không có công việc không được cam kết master, cam kết / đẩy nếu cần, sao chép một bản sao mới của kho lưu trữ và xóa cái cũ.


0

Đối với mục đích này, bạn có thể sử dụng git-bổ sung

$ git delete-merged-branches
Deleted feature/themes (was c029ab3).
Deleted feature/live_preview (was a81b002).
Deleted feature/dashboard (was 923befa).

0

Tôi không có grep hoặc unix khác trên hộp của mình nhưng điều này hoạt động từ thiết bị đầu cuối của VSCode:

git branch -d $(git branch).trim()

Tôi sử dụng chữ thường d để nó không xóa các nhánh không được trộn.

Tôi cũng là chủ nhân khi tôi làm điều đó, vì vậy * masterkhông tồn tại nên đã không cố gắng xóa chủ.


Xác nhận: Nếu không bật master, lệnh này SILL xóa master.
Brett Rowberry

-1

Hãy chắc chắn rằng bạn làm điều này đầu tiên

git fetch

Khi bạn có tất cả thông tin chi nhánh từ xa, hãy sử dụng lệnh sau để xóa mọi nhánh đơn trừ chủ

 git branch -a | grep -v "master" | grep remotes | sed 's/remotes\/origin\///g' | xargs git push origin --delete
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.