Skip to content

Latest commit

 

History

History
490 lines (389 loc) · 35.3 KB

File metadata and controls

490 lines (389 loc) · 35.3 KB

گیت و سابورژن (Git and Subversion)

بخش بزرگی از پروژه‌های متن‌باز و تعداد قابل توجهی از پروژه‌های شرکتی از ساب‌ورژن برای مدیریت کدهای منبعشان استفاده می‌کنند. این ابزار بیش از یک دهه است که وجود دارد و در بیشتر آن مدت، انتخاب پیش‌فرض سیستم کنترل نسخه برای پروژه‌های متن‌باز بوده است. در بسیاری از جهات نیز بسیار شبیه CVS است، که پیش از آن بازیگر اصلی در دنیای کنترل‌نسخه‌ها بود.

یکی از ویژگی‌های برجسته گیت، پل دوجهته‌ای به ساب‌ورژن است به نام git svn. این ابزار به شما اجازه می‌دهد تا از گیت به‌عنوان یک کلاینت معتبر برای یک سرور ساب‌ورژن استفاده کنید، بنابراین می‌توانید از تمام امکانات محلی گیت بهره ببرید و سپس تغییرات را به سرور ساب‌ورژن پوش کنید انگار که محلی از ساب‌ورژن استفاده می‌کنید. این یعنی می‌توانید شاخه‌زنی و ادغام محلی انجام دهید، از منطقهٔ مرحله‌بندی استفاده کنید، ری‌بیس و چری‌پیکینگ به‌کار ببرید و غیره، در حالی که همکارانتان به روش‌های قدیمی و تاریک خود ادامه می‌دهند. این روش خوبی است برای نفوذ آرام گیت به محیط شرکتی و کمک به توسعه‌دهندگان همکار برای افزایش کارایی، در حالی که شما برای تغییر زیرساخت جهت پشتیبانی کامل از گیت تلاش می‌کنید. پل ساب‌ورژن، مادهٔ مخدرِ دروازه‌ای به دنیای DVCS است.

ابزار گیت برای تعامل با Subversion (git svn)

فرمان پایه در گیت برای همهٔ فرمان‌های مرتبط با پل ساب‌ورژن، git svn است. این فرمان مجموعه‌ای از زیرفرمان‌ها را دارد، بنابراین ما رایج‌ترین آن‌ها را هنگام مرور چند گردش‌کار ساده نشان خواهیم داد.

مهم است توجه داشته باشید که وقتی از git svn استفاده می‌کنید، با ساب‌ورژن در تعامل هستید؛ سیستمی که بسیار متفاوت از گیت کار می‌کند. اگرچه می‌توانید شاخه‌زنی و ادغام محلی انجام دهید، معمولاً بهتر است تاریخچه‌تان را تا حد امکان خطی نگه دارید با ری‌بیس کردن کارها، و از کارهایی مانند تعامل هم‌زمان با یک مخزن ریموت گیت پرهیز کنید.

تاریخچه را بازنویسی نکنید و دوباره تلاش به پوش نکنید، و هم‌زمان برای همکاری با دیگر توسعه‌دهندگان گیت به یک مخزن گیت موازی پوش ننمایید. ساب‌ورژن تنها می‌تواند یک تاریخچه خطی داشته باشد و گیج کردن آن بسیار ساده است. اگر با تیمی کار می‌کنید و برخی از اعضا از SVN و برخی دیگر از Git استفاده می‌کنند، مطمئن شوید همه برای همکاری از سرور SVN استفاده می‌کنند — این کار زندگی شما را آسان‌تر خواهد کرد.

راه‌اندازی (Setting Up)

برای نمایش این قابلیت، به یک مخزن معمولی SVN که دسترسی نوشتن به آن دارید نیاز دارید. اگر می‌خواهید این مثال‌ها را کپی کنید، باید یک کپی قابل نوشت از یک مخزن آزمایشی SVN بسازید. برای انجام آسان این کار می‌توانید از ابزاری به نام svnsync استفاده کنید که همراه با Subversion عرضه می‌شود.

برای دنبال کردن مراحل، ابتدا باید یک مخزن محلی جدید Subversion ایجاد کنید:

$ mkdir /tmp/test-svn
$ svnadmin create /tmp/test-svn

سپس، اجازه دهید همه کاربران بتوانند revprop ها را تغییر دهند — راه ساده این است که یک اسکریپت pre-revprop-change اضافه کنید که همیشه با کد خروجی 0 خاتمه می‌یابد:

$ cat /tmp/test-svn/hooks/pre-revprop-change
#!/bin/sh
exit 0;
$ chmod +x /tmp/test-svn/hooks/pre-revprop-change

اکنون می‌توانید این پروژه را با فراخوانی svnsync init با مخازن مبدا و مقصد، به ماشین محلی خود همگام‌سازی کنید.

$ svnsync init file:///tmp/test-svn \
  http://your-svn-server.example.org/svn/

این کار خصوصیات لازم برای اجرای همگام‌سازی را تنظیم می‌کند. سپس می‌توانید با اجرای دستور زیر کد را کلون کنید:

$ svnsync sync file:///tmp/test-svn
Committed revision 1.
Copied properties for revision 1.
Transmitting file data .............................[...]
Committed revision 2.
Copied properties for revision 2.
[…]

اگرچه این عملیات ممکن است تنها چند دقیقه طول بکشد، اما اگر سعی کنید مخزن اصلی را به جای یک مخزن محلی به یک مخزن راه دور دیگر کپی کنید، فرایند تقریباً یک ساعت طول خواهد کشید، حتی اگر کمتر از ۱۰۰ کامیت وجود داشته باشد. ساب‌ورژن باید یک بازنگری را یک‌به‌یک کلون کند و سپس آن را به مخزن دیگر پوش کند — این بسیار ناکارآمد است، اما تنها راه آسان برای انجام این کار است.

شروع به کار (Getting Started)

حالا که یک مخزن Subversion دارید که به آن دسترسی نوشتن دارید، می‌توانید یک جریان کاری معمولی را طی کنید. شما با فرمان git svn clone شروع خواهید کرد که یک مخزن کامل Subversion را به یک مخزن محلی Git وارد می‌کند. به یاد داشته باشید اگر از یک مخزن SVN میزبانی‌شده واقعی وارد می‌کنید، باید file:///tmp/test-svn را با آدرس (URL) مخزن Subversion خود جایگزین کنید:

$ git svn clone file:///tmp/test-svn -T trunk -b branches -t tags
Initialized empty Git repository in /private/tmp/progit/test-svn/.git/
r1 = dcbfb5891860124cc2e8cc616cded42624897125 (refs/remotes/origin/trunk)
    A	m4/acx_pthread.m4
    A	m4/stl_hash.m4
    A	java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
    A	java/src/test/java/com/google/protobuf/WireFormatTest.java

r75 = 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae (refs/remotes/origin/trunk)
Found possible branch point: file:///tmp/test-svn/trunk => file:///tmp/test-svn/branches/my-calc-branch, 75
Found branch parent: (refs/remotes/origin/my-calc-branch) 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae
Following parent with do_switch
Successfully followed parent
r76 = 0fb585761df569eaecd8146c71e58d70147460a2 (refs/remotes/origin/my-calc-branch)
Checked out HEAD:
  file:///tmp/test-svn/trunk r75

این کار معادل اجرای دو فرمان git svn init و سپس git svn fetch روی آدرسی است که وارد می‌کنید. این کار ممکن است مدتی طول بکشد. برای مثال، اگر پروژهٔ آزمایشی فقط حدود ۷۵ کامیت داشته باشد و پایگاه کد هم خیلی بزرگ نباشد، گیت با این حال باید هر نسخه را یکی‌یکی خارج‌کرده (checkout) و جداگانه کامیت کند. برای پروژه‌ای با صدها یا هزاران کامیت، این فرایند عملاً می‌تواند ساعت‌ها یا حتی روزها طول بکشد.

قسمت -T trunk -b branches -t tags به گیت می‌گوید که این مخزن ساب‌ورژن از قراردادهای پایه‌ای شاخه‌بندی و برچسب‌گذاری پیروی می‌کند. اگر نام trunk، branches یا tags شما متفاوت است، می‌توانید این گزینه‌ها را تغییر دهید. از آنجا که این الگو بسیار رایج است، می‌توانید کل این قسمت را با -s جایگزین کنید که به معنای «ساختار استاندارد» بوده و آن گزینه‌ها را ضمنی در بر می‌گیرد. فرمان زیر معادل است:

$ git svn clone file:///tmp/test-svn -s

در این مرحله باید یک مخزن گیت معتبر داشته باشید که شاخه‌ها و برچسب‌های شما را وارد کرده باشد:

$ git branch -a
* master
  remotes/origin/my-calc-branch
  remotes/origin/tags/2.0.2
  remotes/origin/tags/release-2.0.1
  remotes/origin/tags/release-2.0.2
  remotes/origin/tags/release-2.0.2rc1
  remotes/origin/trunk

توجه کنید که این ابزار چگونه برچسب‌های ساب‌ورژن را به صورت refهای راه‌دور مدیریت می‌کند. با فرمان «ابزاری» گیت یعنی show-ref دقیق‌تر نگاه کنیم:

$ git show-ref
556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae refs/heads/master
0fb585761df569eaecd8146c71e58d70147460a2 refs/remotes/origin/my-calc-branch
bfd2d79303166789fc73af4046651a4b35c12f0b refs/remotes/origin/tags/2.0.2
285c2b2e36e467dd4d91c8e3c0c0e1750b3fe8ca refs/remotes/origin/tags/release-2.0.1
cbda99cb45d9abcb9793db1d4f70ae562a969f1e refs/remotes/origin/tags/release-2.0.2
a9f074aa89e826d6f9d30808ce5ae3ffe711feda refs/remotes/origin/tags/release-2.0.2rc1
556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae refs/remotes/origin/trunk

گیت هنگام کلون‌کردن از یک سرور گیت این کار را انجام نمی‌دهد؛ این‌جا نمونه‌ای از ظاهری است که مخزن بعد از یک کلون تازه با برچسب‌ها دارد:

$ git show-ref
c3dcbe8488c6240392e8a5d7553bbffcb0f94ef0 refs/remotes/origin/master
32ef1d1c7cc8c603ab78416262cc421b80a8c2df refs/remotes/origin/branch-1
75f703a3580a9b81ead89fe1138e6da858c5ba18 refs/remotes/origin/branch-2
23f8588dde934e8f33c263c6d8359b2ae095f863 refs/tags/v0.1.0
7064938bd5e7ef47bfd79a685a62c1e2649e2ce7 refs/tags/v0.2.0
6dcb09b5b57875f334f61aebed695e2e4193db5e refs/tags/v1.0.0

گیت برچسب‌ها را مستقیماً در refs/tags دریافت می‌کند، نه این‌که آن‌ها را به‌عنوان شاخه‌های راه‌دور در نظر بگیرد.

بازگرداندن کامیت‌ها به ساب‌ورژن (Committing Back to Subversion)

حالا که یک درخت کاری دارید، می‌توانید روی پروژه کار کنید و کامیت‌های خود را به‌صورت upstream به عقب بفرستید و عملاً از گیت به‌عنوان یک کلاینت SVN استفاده کنید. اگر یکی از فایل‌ها را ویرایش کرده و کامیت کنید، یک کامیت دارید که به‌صورت محلی در گیت وجود دارد اما در سرور ساب‌ورژن وجود ندارد:

$ git commit -am 'Adding git-svn instructions to the README'
[master 4af61fd] Adding git-svn instructions to the README
 1 file changed, 5 insertions(+)

در گام بعد باید تغییر خود را به سرور upstream بفرستید. دقت کنید که این کار نحوهٔ کار با ساب‌ورژن را تغییر می‌دهد — می‌توانید چندین کامیت را آفلاین انجام داده و سپس همهٔ آن‌ها را یکجا به سرور ساب‌ورژن push کنید. برای ارسال به یک سرور ساب‌ورژن، فرمان git svn dcommit را اجرا می‌کنید:

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
    M	README.txt
Committed r77
    M	README.txt
r77 = 95e0222ba6399739834380eb10afcd73e0670bc5 (refs/remotes/origin/trunk)
No changes between 4af61fd05045e07598c553167e0f31c84fd6ffe1 and refs/remotes/origin/trunk
Resetting to the latest refs/remotes/origin/trunk
 این کار تمام commitهایی را که شما روی کد سرور Subversion ساخته‌اید می‌گیرد، برای هر کدام یک commit روی Subversion انجام می‌دهد و سپس commit محلی Git شما را بازنویسی می‌کند تا یک شناسهٔ یکتا را در بر داشته باشد.
این مهم است چون یعنی تمام چک‌سوم‌های SHA-1 مربوط به commitهای شما تغییر می‌کنند.
تا حدی به همین دلیل، هم‌زمان کار کردن با نسخه‌های راه دور مبتنی بر Git از پروژه‌هایتان همراه با یک سرور Subversion ایدهٔ خوبی نیست.
اگر به آخرین commit نگاه کنید، می‌توانید `git-svn-id` جدیدی را که اضافه شده می‌بینید:
$ git log -1
commit 95e0222ba6399739834380eb10afcd73e0670bc5
Author: ben <ben@0b684db3-b064-4277-89d1-21af03df0a68>
Date:   Thu Jul 24 03:08:36 2014 +0000

    Adding git-svn instructions to the README

    git-svn-id: file:///tmp/test-svn/trunk@77 0b684db3-b064-4277-89d1-21af03df0a68

توجه کنید که چک‌سوم SHA-1 که در ابتدا با 4af61fd شروع می‌شد وقتی شما commit کردید اکنون با 95e0222 شروع می‌شود. اگر می‌خواهید به هر دو سرور Git و سرور Subversion push کنید، ابتدا باید به سرور Subversion dcommit کنید، چون آن عملیات داده‌های commit شما را تغییر می‌دهد.

دریافت تغییرات جدید (Pulling in New Changes)

اگر با توسعه‌دهندگان دیگر کار می‌کنید، در مقطعی یکی از شما push خواهد کرد و سپس دیگری سعی می‌کند تغییری را push کند که تداخل دارد. آن تغییر تا زمانی که کارشان را merge نکنید رد خواهد شد. در git svn این شبیه این نشان داده می‌شود:

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...

ERROR from SVN:
Transaction is out of date: File '/trunk/README.txt' is out of date
W: d5837c4b461b7c0e018b49d12398769d2bfc240a and refs/remotes/origin/trunk differ, using rebase:
:100644 100644 f414c433af0fd6734428cf9d2a9fd8ba00ada145 c80b6127dd04f5fcda218730ddf3a2da4eb39138 M	README.txt
Current branch master is up to date.
ERROR: Not all changes have been committed into SVN, however the committed
ones (if any) seem to be successfully integrated into the working tree.
Please see the above messages for details.

برای رفع این وضعیت می‌توانید دستور git svn rebase را اجرا کنید، که هر تغییری را که روی سرور هست و شما هنوز ندارید می‌کشد و هر کاری که شما انجام داده‌اید را دوباره به‌صورت rebase شده روی آنچه روی سرور است قرار می‌دهد:

$ git svn rebase
Committing to file:///tmp/test-svn/trunk ...

ERROR from SVN:
Transaction is out of date: File '/trunk/README.txt' is out of date
W: eaa029d99f87c5c822c5c29039d19111ff32ef46 and refs/remotes/origin/trunk differ, using rebase:
:100644 100644 65536c6e30d263495c17d781962cfff12422693a b34372b25ccf4945fe5658fa381b075045e7702a M	README.txt
First, rewinding head to replay your work on top of it...
Applying: update foo
Using index info to reconstruct a base tree...
M	README.txt
Falling back to patching base and 3-way merge...
Auto-merging README.txt
ERROR: Not all changes have been committed into SVN, however the committed
ones (if any) seem to be successfully integrated into the working tree.
Please see the above messages for details.

حال، تمام کارهای شما روی آنچه روی سرور Subversion است قرار گرفته‌اند، پس می‌توانید با موفقیت dcommit کنید:

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
    M	README.txt
Committed r85
    M	README.txt
r85 = 9c29704cc0bbbed7bd58160cfb66cb9191835cd8 (refs/remotes/origin/trunk)
No changes between 5762f56732a958d6cfda681b661d2a239cc53ef5 and refs/remotes/origin/trunk
Resetting to the latest refs/remotes/origin/trunk

توجه کنید که بر خلاف Git که از شما می‌خواهد قبل از push کردن، کارهای upstream را که هنوز به‌صورت محلی ندارید merge کنید، git svn فقط در صورتی شما را مجبور به این کار می‌کند که تغییرات تداخل داشته باشند (که بسیار شبیه رفتار Subversion است). اگر شخص دیگری تغییری روی یک فایل اعمال کند و سپس شما تغییری را روی فایل دیگری push کنید، dcommit شما بدون مشکل عمل خواهد کرد:

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
    M	configure.ac
Committed r87
    M	autogen.sh
r86 = d8450bab8a77228a644b7dc0e95977ffc61adff7 (refs/remotes/origin/trunk)
    M	configure.ac
r87 = f3653ea40cb4e26b6281cec102e35dcba1fe17c4 (refs/remotes/origin/trunk)
W: a0253d06732169107aa020390d9fefd2b1d92806 and refs/remotes/origin/trunk differ, using rebase:
:100755 100755 efa5a59965fbbb5b2b0a12890f1b351bb5493c18 e757b59a9439312d80d5d43bb65d4a7d0389ed6d M	autogen.sh
First, rewinding head to replay your work on top of it...
 به خاطر سپردن این نکته مهم است، زیرا نتیجه وضعیت پروژه‌ای است که هنگام push روی هیچ‌کدام از دو کامپیوتر شما وجود نداشته است.
اگر تغییرات ناسازگار باشند اما تضاد (conflict) نداشته باشند، ممکن است با مشکلاتی روبه‌رو شوید که تشخیص‌شان دشوار است.
این با استفاده از یک سرور Git متفاوت است — در Git می‌توانید وضعیت را در سیستم کلاینت خود به‌طور کامل تست کنید قبل از اینکه آن را منتشر کنید، در حالی که در SVN هرگز نمی‌توانید مطمئن باشید که وضعیت دقیقاً بلافاصله قبل از commit و بعد از commit یکسان است.

همچنین باید این فرمان را اجرا کنید تا تغییرات از سرور Subversion کشیده شوند، حتی اگر خودتان آمادهٔ commit کردن نباشید. می‌توانید با git svn fetch داده‌های جدید را بگیرید، اما git svn rebase هم fetch را انجام می‌دهد و سپس commitهای محلی شما را به‌روز می‌کند.

$ git svn rebase
    M	autogen.sh
r88 = c9c5f83c64bd755368784b444bc7a0216cc1e17b (refs/remotes/origin/trunk)
First, rewinding head to replay your work on top of it...
Fast-forwarded master to refs/remotes/origin/trunk.

اجرای گاه‌به‌گاه git svn rebase مطمئن می‌سازد که کد شما همیشه به‌روز است. با این حال، هنگام اجرای این فرمان باید مطمئن باشید که شاخهٔ کاری (working directory) شما پاک است. اگر تغییرات محلی دارید، باید یا کارتان را stash کنید یا موقتاً commit کنید قبل از اجرای git svn rebase — در غیر این صورت، اگر rebase منجر به یک conflict شود فرمان متوقف خواهد شد.

مشکلات شاخه های گیت (Git Branching Issues)

وقتی با یک جریان کاری Git راحت شوید، به احتمال زیاد شاخه‌های موضوعی (topic branches) ایجاد خواهید کرد، روی آن‌ها کار می‌کنید و سپس آن‌ها را merge می‌کنید. اگر از طریق git svn به یک سرور Subversion push می‌کنید، ممکن است بخواهید هر بار کارتان را به جای ادغام شاخه‌ها، روی یک شاخهٔ واحد rebase کنید. دلیل ترجیح rebase این است که Subversion تاریخچه‌ای خطی دارد و با mergeها مثل Git برخورد نمی‌کند، بنابراین git svn هنگام تبدیل اسنپ‌شات‌ها به commitهای Subversion فقط از والد اول پیروی می‌کند.

فرض کنید تاریخچهٔ شما شبیه به این است: شما یک شاخهٔ experiment ایجاد کرده‌اید، دو commit انجام داده‌اید، و سپس آن‌ها را به master merge کرده‌اید. وقتی dcommit انجام می‌دهید، خروجی‌ای شبیه به این می‌بینید:

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
    M	CHANGES.txt
Committed r89
    M	CHANGES.txt
r89 = 89d492c884ea7c834353563d5d913c6adf933981 (refs/remotes/origin/trunk)
    M	COPYING.txt
    M	INSTALL.txt
Committed r90
    M	INSTALL.txt
    M	COPYING.txt
r90 = cb522197870e61467473391799148f6721bcf9a0 (refs/remotes/origin/trunk)
No changes between 71af502c214ba13123992338569f4669877f55fd and refs/remotes/origin/trunk
Resetting to the latest refs/remotes/origin/trunk

اجرای دستور dcommit روی برنچی که تاریخچهٔ مرج‌شده دارد به درستی کار می‌کند، اما وقتی به تاریخچهٔ پروژهٔ Git نگاه می‌کنید، هیچ‌کدام از کامیت‌هایی که روی برنچ experiment ساخته‌اید بازنویسی نشده‌اند — در عوض همهٔ آن تغییرات در نسخهٔ SVNِ یک کامیت مرج واحد ظاهر می‌شوند.

وقتی شخص دیگری آن کار را کلون می‌کند، فقط کامیت مرج را می‌بیند که تمام کارها در آن فشرده شده‌اند، انگار که شما git merge --squash اجرا کرده‌اید؛ آنها اطلاعاتی دربارهٔ منبع یا زمان ایجاد آن کامیت را نمی‌بینند.

شاخه‌بندی در Subversion (Subversion Branching)

شاخه‌بندی در Subversion مثل شاخه‌بندی در Git نیست؛ اگر بتوانید تا حد امکان از آن استفاده نکنید، احتمالاً بهتر است. با این حال، می‌توانید با استفاده از git svn شاخه‌هایی در Subversion ایجاد کرده و روی آن‌ها کامیت کنید.

ایجاد یک شاخهٔ جدید در SVN (Creating a New SVN Branch)

برای ایجاد یک شاخهٔ جدید در Subversion، از دستور git svn branch [new-branch] استفاده می‌کنید:

$ git svn branch opera
Copying file:///tmp/test-svn/trunk at r90 to file:///tmp/test-svn/branches/opera...
Found possible branch point: file:///tmp/test-svn/trunk => file:///tmp/test-svn/branches/opera, 90
Found branch parent: (refs/remotes/origin/opera) cb522197870e61467473391799148f6721bcf9a0
Following parent with do_switch
Successfully followed parent
r91 = f1b64a3855d3c8dd84ee0ef10fa89d27f1584302 (refs/remotes/origin/opera)

این معادل دستور svn copy trunk branches/opera در Subversion است و روی سرور Subversion عمل می‌کند. مهم است بدانید که شما را به آن شاخه چک‌اوت نمی‌کند؛ اگر در این مرحله کامیت کنید، آن کامیت به trunk روی سرور خواهد رفت، نه به opera.

تغییر شاخهٔ فعال (Switching Active Branches)

Git با نگاه کردن به سرِ هر یک از شاخه‌های Subversion شما در تاریخچه‌تان تشخیص می‌دهد که dcommitهایتان به کجا می‌روند — باید فقط یکی از آن‌ها وجود داشته باشد، و آن باید آخرین شاخه‌ای باشد که git-svn-id در تاریخچهٔ شاخهٔ فعلی شما دارد.

اگر می‌خواهید هم‌زمان روی بیش از یک شاخه کار کنید، می‌توانید شاخه‌های محلی‌ای را طوری تنظیم کنید که برای dcommit به شاخه‌های مشخص Subversion اشاره کنند و آن‌ها را از کامیت واردشدهٔ Subversion برای آن شاخه شروع کنید. اگر می‌خواهید یک شاخهٔ opera داشته باشید که بتوانید جداگانه رویش کار کنید، می‌توانید اجرا کنید:

$ git branch opera remotes/origin/opera

حالا اگر بخواهید شاخه‌ی opera را درون trunk (شاخه‌ی master شما) ادغام کنید، می‌توانید این کار را با یک git merge معمولی انجام دهید. اما باید یک پیام کامیت توصیفی (با استفاده از -m) بدهید، وگرنه پیام ادغام به‌صورت “Merge branch opera” خواهد بود که مفید نیست.

به خاطر داشته باشید که گرچه برای این عملیات از git merge استفاده می‌کنید و احتمالاً ادغام خیلی ساده‌تر از Subversion خواهد بود (چون گیت به‌صورت خودکار مبنای مناسب ادغام را تشخیص می‌دهد)، این یک کامیت ادغام عادی در گیت نیست. شما باید این داده‌ها را به یک سرور Subversion که قادر به نگهداری یک کامیتی با بیش از یک والد نیست، برگردانید؛ بنابراین بعد از ارسال (push) آن، این‌طور به نظر خواهد رسید که یک کامیت واحد تمام کارهای شاخه‌ی دیگر را زیر یک کامیت فشرده کرده است. بعد از اینکه یک شاخه را در شاخه‌ی دیگر ادغام کردید، به‌سادگی نمی‌توانید برگردید و مثل حالت عادی در گیت روی آن شاخه ادامه‌ی کار بدهید. فرمان dcommit که اجرا می‌کنید هر اطلاعاتی را که نشان دهد کدام شاخه ادغام شده است پاک می‌کند، پس محاسبات بعدی مبنای ادغام اشتباه خواهند شد — dcommit نتیجه‌ی git merge شما را طوری نشان می‌دهد که انگار git merge --squash اجرا شده است. متأسفانه راه خوبی برای اجتناب از این وضعیت وجود ندارد — Subversion قادر به ذخیره‌ی این اطلاعات نیست، بنابراین تا زمانی که از آن به‌عنوان سرور استفاده می‌کنید، همیشه محدودیت‌های آن شما را مختل خواهد کرد. برای جلوگیری از مشکلات، پس از ادغام شاخه در trunk باید شاخه‌ی محلی (در این مثال، opera) را حذف کنید.

دستورات Subversion (Subversion Commands)

مجموعه ابزار git svn تعدادی دستور فراهم می‌کند تا با ارائه‌ی قابلیت‌هایی مشابه آنچه در Subversion داشتید، انتقال به گیت را آسان‌تر کند. در اینجا چند دستور آمده که آنچه Subversion قبلاً ارائه می‌داد را در اختیار شما می‌گذارد.

تاریخچه به سبک SVN (SVN Style History)

اگر به Subversion عادت دارید و می‌خواهید تاریخچه را به قالب خروجی SVN ببینید، می‌توانید با اجرای git svn log تاریخچه‌ی کامیت‌های خود را در قالب‌بندی SVN مشاهده کنید:

$ git svn log
------------------------------------------------------------------------
r87 | schacon | 2014-05-02 16:07:37 -0700 (Sat, 02 May 2014) | 2 lines

autogen change

------------------------------------------------------------------------
r86 | schacon | 2014-05-02 16:00:21 -0700 (Sat, 02 May 2014) | 2 lines

Merge branch 'experiment'

------------------------------------------------------------------------
r85 | schacon | 2014-05-02 16:00:09 -0700 (Sat, 02 May 2014) | 2 lines

updated the changelog
 شما باید دو نکتهٔ مهم را دربارهٔ `git svn log` بدانید.
اول اینکه این دستور به‌صورت آفلاین کار می‌کند، بر خلاف دستور واقعی `svn log` که برای گرفتن اطلاعات از سرور Subversion سؤال می‌پرسد.
دوم اینکه تنها کامیت‌هایی را نشان می‌دهد که تا حالا به سرور Subversion ارسال شده‌اند.
کامیت‌های محلی گیت که هنوز ارسال (dcommited) نشده‌اند نمایش داده نمی‌شوند؛ همچنین کامیت‌هایی که دیگران در این بین به سرور Subversion زده‌اند هم نشان داده نمی‌شوند.
این خروجی بیشتر شبیه آخرین وضعیت شناخته‌شدهٔ کامیت‌ها روی سرور Subversion است.
یادداشت‌گذاری در SVN (SVN Annotation)

همان‌طور که دستور git svn log به‌صورت آفلاین رفتار دستور svn log را شبیه‌سازی می‌کند، می‌توانید معادل svn annotate را با اجرای git svn blame [FILE] به‌دست آورید. خروجی شبیه این خواهد بود:

$ git svn blame README.txt
 2   temporal Protocol Buffers - Google's data interchange format
 2   temporal Copyright 2008 Google Inc.
 2   temporal http://code.google.com/apis/protocolbuffers/
 2   temporal
22   temporal C++ Installation - Unix
22   temporal =======================
 2   temporal
79    schacon Committing in git-svn.
78    schacon
 2   temporal To build and install the C++ Protocol Buffer runtime and the Protocol
 2   temporal Buffer compiler (protoc) execute the following:
 2   temporal

دوباره تاکید می‌شود که این خروجی کامیت‌های محلی شما در گیت یا کامیت‌هایی که در این فاصله به Subversion فرستاده شده‌اند را نشان نمی‌دهد.

اطلاعات سرور SVN (SVN Server Information)

همچنین می‌توانید با اجرای git svn info همان نوع اطلاعاتی را که svn info می‌دهد به‌دست آورید:

$ git svn info
Path: .
URL: https://schacon-test.googlecode.com/svn/trunk
Repository Root: https://schacon-test.googlecode.com/svn
Repository UUID: 4c93b258-373f-11de-be05-5f7a86268029
Revision: 87
Node Kind: directory
Schedule: normal
Last Changed Author: schacon
Last Changed Rev: 87
Last Changed Date: 2009-05-02 16:07:37 -0700 (Sat, 02 May 2009)

این مثل blame و log است از این نظر که آفلاین اجرا می‌شود و تنها تا زمانی به‌روز است که آخرین بار با سرور Subversion ارتباط برقرار کرده‌اید.

نادیده گرفتن آنچه Subversion نادیده می‌گیرد (Ignoring What Subversion Ignores)

اگر مخزن Subversion را کلون کنید و در هر جایی خاصیت‌های svn:ignore تنظیم شده باشند، احتمالاً می‌خواهید فایل‌های .gitignore متناظر را بسازید تا ناخواسته فایل‌هایی را که نباید کامیت شوند، کامیت نکنید. git svn دو دستور برای کمک به این مسئله دارد. اولی git svn create-ignore است که به‌طور خودکار فایل‌های .gitignore متناظر را برایتان ایجاد می‌کند تا کامیت بعدی شما بتواند آن‌ها را شامل شود.

دستور دوم git svn show-ignore است که خطوطی را که باید در یک فایل .gitignore قرار دهید به stdout می‌فرستد تا بتوانید خروجی را به فایل استثنا (exclude) پروژهٔ خود هدایت کنید:

$ git svn show-ignore > .git/info/exclude

به این ترتیب پروژه را با فایل‌های .gitignore پر نمی‌کنید. این گزینه خوب است اگر شما تنها کاربر گیت در یک تیم Subversion هستید و هم‌تیمی‌هایتان نمی‌خواهند فایل‌های .gitignore داخل پروژه باشند.

خلاصهٔ Git-Svn (Git-Svn Summary)

ابزارهای git svn زمانی مفیدند که مجبور به کار با یک سرور Subversion هستید یا در محیط توسعه‌ای قرار دارید که نیاز به اجرای سرور Subversion دارد. با این حال باید آن را همانند یک گیت ناقص درنظر بگیرید، وگرنه در ترجمه بین دو سیستم با مسائلی روبه‌رو می‌شوید که می‌تواند شما و همکارانتان را سردرگم کند. برای جلوگیری از مشکل، سعی کنید از این دستورالعمل‌ها پیروی کنید:

  • یک تاریخچهٔ خطی در گیت نگه دارید که شامل کامیت‌های مرج‌شده توسط git merge نباشد. هر کاری که خارج از شاخهٔ اصلی‌تان انجام می‌دهید را ری‌بیس کنید روی شاخهٔ اصلی؛ آن را مرج نکنید.

  • یک سرور گیت جدا راه‌اندازی نکنید و بر روی آن همکاری نکنید. ممکن است برای تسریع کلون‌ها برای توسعه‌دهندگان جدید یکی داشته باشید، اما چیزی به آن پوش نکنید مگر اینکه در پیام کامیت آن ورودی git-svn-id وجود داشته باشد. حتی ممکن است بخواهید یک هوک pre-receive اضافه کنید که هر پیام کامیت را برای وجود git-svn-id بررسی کند و پوش‌هایی را که شامل کامیت‌هایی بدون این ورودی هستند رد کند.

اگر از این دستورالعمل‌ها پیروی کنید، کار با سرور Subversion قابل تحمل‌تر خواهد بود. با این حال، اگر امکان مهاجرت به یک سرور واقعی گیت وجود دارد، انجام این کار می‌تواند مزایای زیادی برای تیم شما داشته باشد.