คำสั่ง Git เพื่อแสดงไฟล์เฉพาะที่ถูกละเว้นโดย. gitignore


645

ฉันเริ่มเปียกด้วย Git และมีปัญหาต่อไปนี้:

ต้นไม้ต้นกำเนิดโครงการของฉัน:

/
|
+--src/
+----refs/
+----...
|
+--vendor/
+----...

ฉันมีรหัส (ปัจจุบัน MEF) ในสาขาผู้จัดจำหน่ายของฉันที่ฉันจะรวบรวมที่นั่นแล้วย้ายการอ้างอิงไป/src/refsยังที่ที่โครงการเลือกพวกเขามา

ปัญหาของฉันเป็นที่ฉันมีของฉัน.gitignoreชุดที่จะไม่สนใจและ*.dll *.pdbฉันสามารถทำได้git add -f bar.dllเพื่อบังคับให้เพิ่มไฟล์ที่ถูกละเว้นซึ่งก็โอเคปัญหาคือฉันไม่สามารถหารายการไฟล์ที่มีอยู่ที่ถูกละเว้นได้

ฉันต้องการแสดงรายการไฟล์ที่ถูกละเว้นเพื่อให้แน่ใจว่าฉันจะไม่ลืมที่จะเพิ่ม

ฉันอ่าน man page git ls-filesแล้วและไม่สามารถใช้งานได้ ดูเหมือนว่าฉันgit ls-files --exclude-standard -iควรทำในสิ่งที่ฉันต้องการ ฉันพลาดอะไรไป


12
วันนี้คุณจะไม่ใช้ Git-LS-ไฟล์ แต่ 'คอมไพล์ LS-ไฟล์'
wojo

7
ผมสารภาพกับคุณที่จะตรวจสอบคำตอบ riyad ของถูกต้องนับว่าเป็นเพียงคนเดียวที่ยอมรับว่าไม่มีการรับประกันวิธีการทำโดยใช้เพียงคำสั่งคอมไพล์ (รวมทั้งgit cleanเคล็ดลับ) ที่แสดงให้เห็นที่นี่ นอกจากนี้เราขอแนะนำให้ใช้ตัวอย่าง "แยกออกจาก" ในข้อมูลสรุปของคุณเนื่องจากที่จริงแล้วไม่สนใจไฟล์. gitignore ใด ๆ ฉันถามสิ่งนี้เป็นพิเศษเพราะหน้านี้เป็นคำตอบยอดนิยมของ Google
Alexander Bird

จุดด่วนที่ "สรุปสิ่งที่ใช้งานได้": หน้า man "Git ls-files" อธิบายว่า "-i" หมายถึงรวมไฟล์ที่ไม่รวมสำหรับเอาต์พุต ls ฉันมีความเข้าใจผิดเหมือนกันจนกระทั่งฉันอ่าน 'ช้า' ;-)
จะ

2
คำตอบควรไปในโพสต์คำตอบและไม่ได้อยู่ในการแก้ไขคำถาม
Flimm

ฉันมีgit config --global alias.ls ls-files --exclude-standardและนั่นทำให้คำตอบสำหรับคำถามgit ls -iนี้
jthill

คำตอบ:


662

หมายเหตุ:


ที่น่าสนใจ (ที่กล่าวถึงในคำตอบของqwertymk ) คุณสามารถใช้คำสั่งอย่างน้อยใน Unix ( ไม่สามารถใช้งานได้ในเซสชันCMD Windows )git check-ignore -v

git check-ignore *
git check-ignore -v *

อันที่สองแสดงกฎที่แท้จริง.gitignoreซึ่งทำให้ไฟล์ถูกละเว้นใน repo git ของคุณ
บน Unix การใช้ " สิ่งที่จะขยายไปยังไฟล์ทั้งหมดในไดเรกทอรีปัจจุบันซ้ำ? " และ bash4 +:

git check-ignore **/*

(หรือfind -execคำสั่ง)

หมายเหตุ: https://stackoverflow.com/users/351947/Rafi B.แนะนำในการแสดงความคิดเห็นเพื่อหลีกเลี่ยงลูกโลก (ความเสี่ยง) :

git check-ignore -v $(find . -type f -print)

ตรวจสอบให้แน่ใจว่าได้แยกไฟล์ออกจาก.git/โฟลเดอร์ย่อยแล้ว


คำตอบเดิม 42009)

git ls-files -i

ควรทำงานยกเว้นรหัสแหล่งที่มาของมันบ่งชี้:

if (show_ignored && !exc_given) {
                fprintf(stderr, "%s: --ignored needs some exclude pattern\n",
                        argv[0]);

exc_given ?

ปรากฎว่ามันจำเป็นต้องมีพารามิเตอร์อีกหนึ่งหลังจากที่-iรายการจริงอะไร:

ลอง:

git ls-files -i --exclude-from=[Path_To_Your_Global].gitignore

(แต่นั่นจะแสดงรายการวัตถุที่แคช (ไม่เพิกเฉย) พร้อมตัวกรองดังนั้นจึงไม่ใช่สิ่งที่คุณต้องการ)


ตัวอย่าง:

$ cat .git/ignore
# ignore objects and archives, anywhere in the tree.
*.[oa]
$ cat Documentation/.gitignore
# ignore generated html files,
*.html
# except foo.html which is maintained by hand
!foo.html
$ git ls-files --ignored \
    --exclude='Documentation/*.[0-9]' \
    --exclude-from=.git/ignore \
    --exclude-per-directory=.gitignore

ที่จริงแล้วในไฟล์ 'gitignore' ของฉัน (เรียกว่า 'แยก') ฉันพบบรรทัดคำสั่งที่สามารถช่วยคุณได้:

F:\prog\git\test\.git\info>type exclude
# git ls-files --others --exclude-from=.git/info/exclude
# Lines that start with '#' are comments.
# For a project mostly in C, the following would be a good set of
# exclude patterns (uncomment them if you want to use them):
# *.[oa]
# *~

ดังนั้น....

git ls-files --others --ignored --exclude-from=.git/info/exclude
git ls-files -o -i --exclude-from=.git/info/exclude

git ls-files --others --ignored --exclude-standard
git ls-files -o -i --exclude-standard

ควรทำเคล็ดลับ

ดังที่ได้กล่าวไว้ในหน้า man ของ ls-filesซึ่ง--othersเป็นส่วนสำคัญในการแสดงไฟล์ที่ไม่ได้แคช, ไม่ได้ถูกคอมมิตและไม่สนใจ

--exclude_standardไม่ได้เป็นเพียงทางลัด แต่เป็นวิธีการรวมการตั้งค่า "รูปแบบที่ละเว้น" มาตรฐานทั้งหมด

exclude-standard
เพิ่มการยกเว้นคอมไพล์มาตรฐาน.git/info/exclude, ในแต่ละไดเรกทอรีและ.gitignoreuser's global exclusion file


@VocC จากความเข้าใจของฉันเกี่ยวกับการทดสอบเหล่านี้คำตอบที่คุณแนะนำที่ด้านบนอาจมีข้อบกพร่องมากมาย นั่นเป็นเหตุผลที่ฉันมักจะแนะนำคำตอบของริยาดแทน
Alexander Bird

2
ตั้งแต่ Git v2.13.2 Release: git status --ignoredดูเหมือนว่ามันจะแสดงไฟล์ที่ไม่ได้ติดตาม: github.com/git/git/blob/master/Documentation/RelNotes/ ......
Pau

1
ว้าวใช้git check-ignore -v *งานได้ดีเพราะมันแสดงให้เห็นว่าการกำหนดค่าที่ใช้ ขอบคุณ.
Hoang Tran

@MikeD หากต้องการให้* /ทำงาน (หรือที่จริงคุณสามารถทำได้ **) คุณต้องตั้งค่า globstar shopt -s globstarหลังจากนั้นควรจะทำงาน
Veda

ไม่ได้เปิดใช้งาน (ความเสี่ยง) globstar:git check-ignore -v $(find . -type f -print)
rafi

482

มีวิธีที่ง่ายกว่ามากในการทำ (git 1.7.6+):

git status --ignored

ดูมีวิธีบอกสถานะ git ให้เพิกเฉยต่อผลกระทบของไฟล์. gitignore หรือไม่


3
คุณใช้คอมไพล์รุ่นใด การเหมืองแร่ (1.7.0.4) error: unknown option 'ignored'กล่าวว่า แม้การเพิ่ม-sตามที่แนะนำในโพสต์ที่เชื่อมโยงก็ใช้งานไม่ได้
Alexander Bird

3
รุ่นของฉันคือ 1.7.6 อีกรุ่น 1.7.5.1 -sเป็นสิ่งหนึ่งที่จำเป็นต้องใช้ คุณอาจลองgit status -hดูว่า--ignoredได้รับการสนับสนุนหรือไม่
Penghe Geng

1
ฉันเดาว่ายังไม่รองรับเพียงแค่ใน 1.7.0.4 คอมพิวเตอร์เครื่องอื่นของฉันมี 1.7.9 และ - กำหนดธงไว้ที่นั่น
Alexander Bird

4
ฉันลองทุกวิธีในหน้านี้ นี่คือสิ่งที่ดีที่สุด มันแสดงทั้งไฟล์และไดเรกทอรี คุณลักษณะนี้อาจไม่สามารถใช้งานได้เมื่อมีการถามคำถามนี้ (โดยวิธีการทั้งหมดของการแก้ปัญหาจะไม่ทำงานอย่างถูกต้องกับแบรนด์ใหม่ "คอมไพล์ init" จนกว่าคุณจะได้อย่างน้อยฉากการเปลี่ยนแปลง.)
wisbucky

12
นี่เป็นสิ่งที่ดีกว่าคำตอบที่ได้รับการยอมรับอย่างแน่นอน นอกจากนี้ยังปลอดภัยกว่าgit clean -ndXโซลูชันเนื่องจากสถานการณ์ที่ไม่ค่อยเกิดขึ้นเมื่อมีคนลืมความผิดพลาดของสถานะจะมีผลกระทบที่ไม่สามารถเพิกถอนได้ในพื้นที่เก็บข้อมูลเนื่องจากไฟล์ที่ไม่ได้ติดตามจะถูกลบ ดังนั้นมันจึงเป็นอันตราย ในทางตรงกันข้ามgit status --ignoredปลอดภัยเสมอแม้เมื่อพิมพ์ผิดและเป็นธรรมชาติที่ต้องจำ
Ioannis Filippidis

400

ตัวเลือกอื่นที่ค่อนข้างสะอาด (ไม่มีการเล่นสำนวน)

git clean -ndX

คำอธิบาย:

$ git help clean

git-clean - Remove untracked files from the working tree
-n, --dry-run - Don't actually remove anything, just show what would be done.
-d - Remove untracked directories in addition to untracked files.
-X - Remove only files ignored by Git.

หมายเหตุ: วิธีนี้จะไม่แสดงไฟล์ที่ถูกละเว้นซึ่งถูกลบไปแล้ว


ดี ... แต่เหตุผลที่ฉันถามคำถามเดิมคือเพื่อให้ฉันสามารถตรวจสอบให้แน่ใจว่าไฟล์ผู้ขาย (* .dll) ที่ควรจะมีนั่นคือ ... ดังนั้นการลบพวกเขาจะไม่เป็นผลลัพธ์ที่ต้องการ อย่างไร: นี่เป็นการดีที่จะรู้ว่าฉันได้เปลี่ยนกลยุทธ์ของฉันจากการไม่สนใจ * .dll เป็นการละเว้นโฟลเดอร์ผลลัพธ์การสร้างของฉัน (แต่ไม่ใช่โฟลเดอร์ผู้จำหน่ายของฉัน) นี่จะเป็นทางเลือกที่ดีmake cleanและเป็นประโยชน์อย่างมากในการสร้างเซิร์ฟเวอร์
Andrew Burns

2
ฉันใช้ git เวอร์ชั่น 1.7.0.4 และทั้งสองคำสั่ง ('git ls-files -o -i --exclude-standard', 'git clean -dXn') ไม่เท่ากัน ไฟล์แรกแสดงไฟล์ให้ฉัน 4 ไฟล์และไฟล์ที่สองเป็นไฟล์ที่สองเท่านั้น (.gitignore ~, index.php ~, sql / create_users.sql ~, www / index.php ~) (จะลบ. gitignore ~, จะลบ index.php ~) ฉันคิดถึงสิ่งที่นี่หรือไม่
Cesar

@VonC น่ารักจัง! ขอบคุณ! @ ซีซาร์ฉันไม่แน่ใจ git ls-files -o -i --exclude-standardผมไม่คุ้นเคยกับ git clean -dXnเป็นสิ่งที่ฉันต้องการเสมอ แต่ไม่แสดงไฟล์ที่ถูกละเว้นซึ่งถูกลบไปแล้ว git ls-files -o -i --exclude-standardอาจทำเช่นนั้น นั่นอาจเป็นสิ่งที่ทำให้เกิดความแตกต่าง
ma11hew28

3
สิ่งหนึ่งเล็ก ๆ - มันเป็นความคิดที่ดีที่จะพิมพ์โอกาสnแรกที่มีโอกาสน้อยกว่าในการลบแบบนั้น git clean -ndX
โทเบียสโคเฮน

1
@TobiasCohen ดี! ฉันอัปเดตคำตอบพร้อมกับข้อเสนอแนะของคุณ มันปลอดภัยกว่า แม้ว่าคุณจะไม่ได้ใช้nGit fatal: clean.requireForce defaults to true and neither -n nor -f given; refusing to cleanก็ตาม ยังคงปลอดภัยอยู่ แต่การพิมพ์nครั้งแรกนั้นปลอดภัยกว่า! :)
ma11hew28

39

แม้ว่าโดยทั่วไปการแก้ไขปัญหาของคุณจะไม่ทำงานในทุกสถานการณ์ สมมติว่า repo dir เช่นนี้

# ls **/*                                                                                                       
doc/index.html  README.txt  tmp/dir0/file0  tmp/file1  tmp/file2

doc:
index.html

tmp:
dir0  file1  file2

tmp/dir0:
file0

และ. gignignore เช่นนี้:

# cat .gitignore
doc
tmp/*

นี้ละเว้นไดเรกทอรีและไฟล์ทั้งหมดด้านล่างdoc tmpGit ทำงานได้ตามที่คาดไว้ แต่คำสั่งที่กำหนดไว้สำหรับการแสดงรายการไฟล์ที่ถูกละเว้นไม่ทำงาน ให้ดูที่สิ่งที่คอมไพล์ได้พูด:

# git ls-files --others --ignored --exclude-standard                                                            
tmp/file1
tmp/file2

ประกาศที่docหายไปจากรายชื่อ คุณสามารถรับมันด้วย:

# git ls-files --others --ignored --exclude-standard --directory                                                
doc/

สังเกตเห็น--directoryตัวเลือกเพิ่มเติม

จากความรู้ของฉันไม่มีคำสั่งเดียวที่จะแสดงรายการไฟล์ที่ถูกละเว้นทั้งหมดในครั้งเดียว แต่ฉันไม่รู้ว่าทำไมtmp/dir0ไม่ปรากฏเลย


2
นี่ทำให้ฉันได้สิ่งที่ฉันต้องการในขณะที่คนอื่นไม่ได้ (สำหรับกรณีของฉันโดยเฉพาะ) ... ขอบคุณ! มันน่าผิดหวังที่ต้องรันคำสั่งสองคำสั่ง แต่ด้วยไดเรกทอรีที่ถูกเพิกเฉยตัวเลือก - ไดเรกทอรีอย่างน้อยก็พบว่าฉันและฉันสามารถไปป์นั้นลงในคำสั่ง find เพื่อค้นหาไฟล์ ขอบคุณ!
lindes

มันทำได้ทั้งหมดในครั้งเดียวและขยายไดเรกตอรี:(git ls-files -oi --exclude-standard; git ls-files -oi --exclude-standard --directory) | perl -nle '$seen{$_}++||next;if(-d){system"find",$_,"-type","f"}else{print}'
Dee Newcum

17

ตอนนี้ Git มีฟังก์ชันการทำงานนี้ในตัวแล้ว

git check-ignore *

แน่นอนคุณสามารถเปลี่ยนรูปแบบให้เป็นแบบ**/*.dllในกรณีของคุณ

อ้างอิง Git


7
git check-ignore **/*เพื่อรวมไฟล์ในไดเรกทอรีย่อย
mzimmer

นี่เป็นเพียงรายการ dicrectories ระดับบนสุดเท่านั้น
Radon8472

13

มันควรจะเพียงพอที่จะใช้

git ls-files --others -i --exclude-standard

ตามที่ครอบคลุมทุกอย่างที่ครอบคลุม

git ls-files --others -i --exclude-from=.git/info/exclude

ดังนั้นหลังจึงซ้ำซ้อน


คุณสามารถทำให้ง่ายขึ้นโดยเพิ่มนามแฝงลงใน~/.gitconfigไฟล์ของคุณ:

git config --global alias.ignored "ls-files --others -i --exclude-standard"

ตอนนี้คุณสามารถพิมพ์git ignoredเพื่อดูรายการ ง่ายต่อการจดจำและพิมพ์ได้เร็วขึ้น

หากคุณต้องการจอแสดงผลที่กระชับยิ่งขึ้นของโซลูชันของ Jason Geng คุณสามารถเพิ่มชื่อแทนสำหรับสิ่งนี้:

git config --global alias.ignored "status --ignored -s"

อย่างไรก็ตามเอาต์พุต verbose มากขึ้นมีประโยชน์มากขึ้นสำหรับการแก้ไขปัญหาเกี่ยวกับไฟล์. gitignore ของคุณเนื่องจากจะแสดงไฟล์ฝ้ายพิกกิ้งเดี่ยวทุกไฟล์ที่ถูกละเว้น โดยปกติแล้วคุณจะไพพ์ผลลัพธ์ผ่านgrepเพื่อดูว่าไฟล์ที่คุณคาดว่าจะถูกเพิกเฉยนั้นอยู่ในนั้นหรือไม่หรือไฟล์ที่คุณไม่ต้องการเพิกเฉยนั้นอยู่ในนั้นหรือไม่

git ignored | grep some-file-that-isnt-being-ignored-properly

จากนั้นเมื่อคุณต้องการเห็นจอแสดงผลแบบสั้น ๆ ก็ง่ายต่อการจดจำและพิมพ์

git status --ignored

(โดย-sปกติสามารถปล่อยทิ้งไว้ได้)


สิ่งนี้ไม่ได้ผลสำหรับฉันเพราะคุณต้องทำรายการไฟล์เหล่านั้นด้วยตนเอง git status --ignoredใช้งานได้กับ Debian sid แต่อาจจะใหม่มาก… แต่เห็นได้ชัดว่ามันเพิ่มเข้ามาเนื่องจากความต้องการที่เป็นที่นิยม ;-)
mirabilos

1
โดย "ทำงานบน Debian sid" ฉันถือว่าคุณหมายถึง "ทำงานกับรุ่น Git ที่ติดตั้งโดยค่าเริ่มต้นบน Debian sid" หรือไม่ คุณควรหลีกเลี่ยงการปล่อยให้ตัวเองถูกจับเป็นตัวประกันโดยเวอร์ชั่นของยูทิลิตี้ที่รวมอยู่ใน distro ของคุณ คุณสามารถอัพเกรดพวกเขาเป็นอิสระจาก distro เอง
iconoclast

12

ต่อไปนี้เป็นวิธีพิมพ์รายการไฟล์ทั้งหมดในแผนผังการทำงานซึ่งจับคู่รูปแบบที่อยู่ในแหล่ง gitignore หลายแหล่งของ Git (ถ้าคุณใช้ GNU find):

$ cd {your project directory}
$ find . -path ./.git -prune -o -print \
| git check-ignore --no-index --stdin --verbose

มันจะตรวจสอบไฟล์ทั้งหมดในสาขาปัจจุบันของพื้นที่เก็บข้อมูล (เว้นแต่คุณจะลบพวกเขาในเครื่อง)

และมันจะระบุบรรทัดซอร์ส gitignore โดยเฉพาะเช่นกัน

Git ยังคงติดตามการเปลี่ยนแปลงในบางไฟล์ที่ตรงกับรูปแบบ gitignore เพียงเพราะไฟล์เหล่านั้นถูกเพิ่มเข้าไปแล้ว มีประโยชน์คำสั่งดังกล่าวจะแสดงไฟล์เหล่านั้นเช่นกัน

รูปแบบ gitignore เชิงลบจะจับคู่เช่นกัน !แต่เหล่านี้มีความแตกต่างได้อย่างง่ายดายในรายชื่อเพราะพวกเขาเริ่มต้นด้วย

หากคุณใช้ Windows Git Bash จะมี GNU find(เปิดเผยโดยfind --version)

หากรายการมีความยาว (และคุณมีrev) คุณสามารถแสดงได้ตามนามสกุล (บ้าง) เช่นกัน:

$ cd {your project directory}
$ find . -path ./.git -prune -o -print \
| git check-ignore --no-index --stdin --verbose \
| rev | sort | rev

สำหรับรายละเอียดเพิ่มเติมโปรดดูman find, man git-check-ignore, และman revman sort

ประเด็นของวิธีการทั้งหมดนี้คือ Git (ซอฟต์แวร์) มีการเปลี่ยนแปลงอย่างรวดเร็วและมีความซับซ้อนสูง ในทางตรงกันข้าม GNU findนั้นมีความเสถียรสูง (อย่างน้อยก็ในคุณสมบัติที่ใช้ที่นี่) ดังนั้นทุกคนที่ปรารถนาจะแข่งขันด้วยการแสดงความรู้เชิงลึกของ Git จะตอบคำถามในวิธีที่แตกต่าง

คำตอบที่ดีที่สุดคืออะไร คำตอบนี้ช่วยลดการพึ่งพาความรู้ของ Git อย่างจงใจเพื่อให้บรรลุเป้าหมายของความมั่นคงและความเรียบง่ายผ่าน modularity (การแยกข้อมูล) และได้รับการออกแบบมาเป็นเวลานาน


ขอบคุณมาก! ฉันพยายามดิ้นรนเพื่อหาสาเหตุว่าทำไมไฟล์แหล่งข้อมูลใหม่ของฉันบางครั้งก็หายไปจากความมุ่งมั่นของฉัน ปรากฎว่าฉันมีรูปแบบ: bin * ที่ฉันคิดว่าจะตรงกับชื่อของไฟล์ / ไดเรกทอรีที่เริ่มต้นด้วย bin เท่านั้น แต่มันตรงกับสิ่งที่มี bin ในเส้นทางแบบเต็มของไฟล์ / ไดเรกทอรี! ฉันเดาว่าปัญหาของฉันมาจากความเข้าใจผิดเกี่ยวกับความหมายที่แม่นยำของการจับคู่รูปแบบใน. gitignore สคริปต์ 2 บรรทัดของคุณช่วยฉันหาข้อผิดพลาดนี้!
Nicolas Rouquette

1

(ขยายคำตอบอื่น ๆ )

หมายเหตุgit check-ignoreใช้ความมุ่งมั่น.gitignoreและไม่ใช่ในแผนผังการทำงานของคุณ! git commit --amendจะเล่นกับมันโดยไม่ก่อให้เกิดมลพิษประวัติศาสตร์คอมไพล์ของคุณคุณได้อย่างอิสระอาจพยายามที่จะแก้ไขมันแล้วกระทำด้วย

ปัญหานี้เกิดขึ้นส่วนใหญ่หากคุณต้องการแก้ไขปัญหา git นั้นไม่ได้ติดตามไดเรกทอรี ใส่ใน.gitignore:

dirtokeep/**
!dirtokeep/.keep

.keepdirtokeepควรเป็นไฟล์ความยาวเป็นศูนย์ใน

ผลลัพธ์จะเป็นว่าทุกอย่างในdirtokeepจะถูกละเว้นยกเว้น dirtokeep/.keepซึ่งจะส่งผลให้dirtokeepไดเรกทอรีจะถูกสร้างขึ้นบนโคลน / เช็คเอาต์


0

สมมติว่ามีบางไดเรกทอรีที่ไม่สนใจทำไมไม่ใช้ "โหนดสถานะ git / logs /" ซึ่งจะบอกคุณว่าไฟล์ที่จะเพิ่ม? ในไดเรกทอรีฉันมีไฟล์ข้อความที่ไม่ได้เป็นส่วนหนึ่งของสถานะเอาท์พุทเช่น:

ในสาขาหลักสาขา
ของคุณทันสมัยกับ 'ต้นกำเนิด / ต้นแบบ'
ไฟล์ที่ไม่ได้ติดตาม:
(ใช้ "git add ... " เพื่อรวมในสิ่งที่จะส่ง)

    node/logs/.gitignore 

. gitignore คือ:

*

! .gitignore

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.